Merge "Revert "Incorrect behavior of View clear focus.""
diff --git a/Android.mk b/Android.mk
index 83c4b5b..79f6220 100644
--- a/Android.mk
+++ b/Android.mk
@@ -67,7 +67,6 @@
 	core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
 	core/java/android/app/IActivityController.aidl \
 	core/java/android/app/IActivityPendingResult.aidl \
-	core/java/android/app/IActivityWatcher.aidl \
 	core/java/android/app/IAlarmManager.aidl \
 	core/java/android/app/IBackupAgent.aidl \
 	core/java/android/app/IInstrumentationWatcher.aidl \
@@ -94,6 +93,7 @@
 	core/java/android/bluetooth/IBluetoothHealthCallback.aidl \
 	core/java/android/bluetooth/IBluetoothPbap.aidl \
 	core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
+	core/java/android/content/ICancellationSignal.aidl \
 	core/java/android/content/IClipboard.aidl \
 	core/java/android/content/IContentService.aidl \
 	core/java/android/content/IIntentReceiver.aidl \
@@ -109,6 +109,7 @@
 	core/java/android/content/pm/IPackageMoveObserver.aidl \
 	core/java/android/content/pm/IPackageStatsObserver.aidl \
 	core/java/android/database/IContentObserver.aidl \
+	core/java/android/hardware/ISerialManager.aidl \
 	core/java/android/hardware/usb/IUsbManager.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
@@ -449,8 +450,6 @@
 		            resources/samples/training/ads-and-ux "Mobile Advertisement Integration" \
 		-samplecode $(sample_dir)/MultiResolution \
 		            resources/samples/MultiResolution "Multiple Resolutions" \
-		-samplecode $(sample_dir)/NFCDemo \
-		            resources/samples/NFCDemo "NFC Demo" \
 		-samplecode $(sample_dir)/training/multiscreen/newsreader \
 		            resources/samples/newsreader "News Reader" \
 		-samplecode $(sample_dir)/NotePad \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index fb334fc..d74d7b1 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -117,6 +117,8 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/fonts/DroidSans*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/content)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/api/16.txt b/api/16.txt
index 8e07844..be544de 100644
--- a/api/16.txt
+++ b/api/16.txt
@@ -15052,7 +15052,7 @@
     method public static final deprecated boolean supportsProcesses();
     field public static final int BLUETOOTH_GID = 2000; // 0x7d0
     field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
-    field public static final int LAST_APPLICATION_UID = 99999; // 0x1869f
+    field public static final int LAST_APPLICATION_UID = 19999; // 0x1869f
     field public static final int PHONE_UID = 1001; // 0x3e9
     field public static final int SIGNAL_KILL = 9; // 0x9
     field public static final int SIGNAL_QUIT = 3; // 0x3
diff --git a/api/current.txt b/api/current.txt
index 8d6a135..97be454 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -436,7 +436,7 @@
     field public static final int fadeEnabled = 16843390; // 0x101027e
     field public static final int fadeOffset = 16843383; // 0x1010277
     field public static final int fadeScrollbars = 16843434; // 0x10102aa
-    field public static final deprecated int fadingEdge = 16842975; // 0x10100df
+    field public static final int fadingEdge = 16842975; // 0x10100df
     field public static final int fadingEdgeLength = 16842976; // 0x10100e0
     field public static final int fastScrollAlwaysVisible = 16843573; // 0x1010335
     field public static final int fastScrollEnabled = 16843302; // 0x1010226
@@ -562,6 +562,7 @@
     field public static final int isRepeatable = 16843336; // 0x1010248
     field public static final int isScrollContainer = 16843342; // 0x101024e
     field public static final int isSticky = 16843335; // 0x1010247
+    field public static final int isolatedProcess = 16843687; // 0x10103a7
     field public static final int itemBackground = 16843056; // 0x1010130
     field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
     field public static final int itemPadding = 16843565; // 0x101032d
@@ -991,6 +992,7 @@
     field public static final int textColorTertiary = 16843282; // 0x1010212
     field public static final int textColorTertiaryInverse = 16843283; // 0x1010213
     field public static final int textCursorDrawable = 16843618; // 0x1010362
+    field public static final int textDirection = 16843688; // 0x10103a8
     field public static final int textEditNoPasteWindowLayout = 16843541; // 0x1010315
     field public static final int textEditPasteWindowLayout = 16843540; // 0x1010314
     field public static final int textEditSideNoPasteWindowLayout = 16843615; // 0x101035f
@@ -2288,7 +2290,8 @@
     method public long getStagger(int);
     method public long getStartDelay(int);
     method public java.util.List<android.animation.LayoutTransition.TransitionListener> getTransitionListeners();
-    method public void hideChild(android.view.ViewGroup, android.view.View);
+    method public deprecated void hideChild(android.view.ViewGroup, android.view.View);
+    method public void hideChild(android.view.ViewGroup, android.view.View, int);
     method public boolean isChangingLayout();
     method public boolean isRunning();
     method public void removeChild(android.view.ViewGroup, android.view.View);
@@ -2300,7 +2303,8 @@
     method public void setInterpolator(int, android.animation.TimeInterpolator);
     method public void setStagger(int, long);
     method public void setStartDelay(int, long);
-    method public void showChild(android.view.ViewGroup, android.view.View);
+    method public deprecated void showChild(android.view.ViewGroup, android.view.View);
+    method public void showChild(android.view.ViewGroup, android.view.View, int);
     field public static final int APPEARING = 2; // 0x2
     field public static final int CHANGE_APPEARING = 0; // 0x0
     field public static final int CHANGE_DISAPPEARING = 1; // 0x1
@@ -2347,6 +2351,15 @@
     method public void setPropertyName(java.lang.String);
   }
 
+  public class TimeAnimator extends android.animation.ValueAnimator {
+    ctor public TimeAnimator();
+    method public void setTimeListener(android.animation.TimeAnimator.TimeListener);
+  }
+
+  public static abstract interface TimeAnimator.TimeListener {
+    method public abstract void onTimeUpdate(android.animation.TimeAnimator, long, long);
+  }
+
   public abstract interface TimeInterpolator {
     method public abstract float getInterpolation(float);
   }
@@ -2400,6 +2413,16 @@
 
 }
 
+package android.annotation {
+
+  public abstract class SuppressLint implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class TargetApi implements java.lang.annotation.Annotation {
+  }
+
+}
+
 package android.app {
 
   public abstract class ActionBar {
@@ -4658,7 +4681,8 @@
 
   public abstract class AsyncTaskLoader extends android.content.Loader {
     ctor public AsyncTaskLoader(android.content.Context);
-    method public boolean cancelLoad();
+    method public void cancelLoadInBackground();
+    method public boolean isLoadInBackgroundCanceled();
     method public abstract D loadInBackground();
     method public void onCanceled(D);
     method protected D onLoadInBackground();
@@ -4701,6 +4725,18 @@
     method public final void setResultExtras(android.os.Bundle);
   }
 
+  public final class CancellationSignal {
+    ctor public CancellationSignal();
+    method public void cancel();
+    method public boolean isCanceled();
+    method public void setOnCancelListener(android.content.CancellationSignal.OnCancelListener);
+    method public void throwIfCanceled();
+  }
+
+  public static abstract interface CancellationSignal.OnCancelListener {
+    method public abstract void onCancel();
+  }
+
   public class ClipData implements android.os.Parcelable {
     ctor public ClipData(java.lang.CharSequence, java.lang.String[], android.content.ClipData.Item);
     ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
@@ -4820,6 +4856,7 @@
     method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
     method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal);
     method protected final void setPathPermissions(android.content.pm.PathPermission[]);
     method protected final void setReadPermission(java.lang.String);
     method protected final void setWritePermission(java.lang.String);
@@ -4843,6 +4880,7 @@
     method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
+    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal) throws android.os.RemoteException;
     method public boolean release();
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
   }
@@ -4929,6 +4967,7 @@
     method public final java.io.OutputStream openOutputStream(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal);
     method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
     method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
     method public static void removeStatusChangeListener(java.lang.Object);
@@ -5351,6 +5390,7 @@
     method public static android.content.Intent makeMainActivity(android.content.ComponentName);
     method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
     method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName);
+    method public static java.lang.String normalizeMimeType(java.lang.String);
     method public static android.content.Intent parseIntent(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.Intent parseUri(java.lang.String, int) throws java.net.URISyntaxException;
     method public android.content.Intent putCharSequenceArrayListExtra(java.lang.String, java.util.ArrayList<java.lang.CharSequence>);
@@ -5399,13 +5439,16 @@
     method public android.content.Intent setClassName(java.lang.String, java.lang.String);
     method public android.content.Intent setComponent(android.content.ComponentName);
     method public android.content.Intent setData(android.net.Uri);
+    method public android.content.Intent setDataAndNormalize(android.net.Uri);
     method public android.content.Intent setDataAndType(android.net.Uri, java.lang.String);
+    method public android.content.Intent setDataAndTypeAndNormalize(android.net.Uri, java.lang.String);
     method public void setExtrasClassLoader(java.lang.ClassLoader);
     method public android.content.Intent setFlags(int);
     method public android.content.Intent setPackage(java.lang.String);
     method public void setSelector(android.content.Intent);
     method public void setSourceBounds(android.graphics.Rect);
     method public android.content.Intent setType(java.lang.String);
+    method public android.content.Intent setTypeAndNormalize(java.lang.String);
     method public deprecated java.lang.String toURI();
     method public java.lang.String toUri(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -5607,6 +5650,7 @@
     field public static final int FLAG_GRANT_READ_URI_PERMISSION = 1; // 0x1
     field public static final int FLAG_GRANT_WRITE_URI_PERMISSION = 2; // 0x2
     field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
+    field public static final int FLAG_RECEIVER_FOREGROUND = 268435456; // 0x10000000
     field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
     field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
     field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
@@ -5731,7 +5775,9 @@
   public class Loader {
     ctor public Loader(android.content.Context);
     method public void abandon();
+    method public boolean cancelLoad();
     method public java.lang.String dataToString(D);
+    method public void deliverCancellation();
     method public void deliverResult(D);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public void forceLoad();
@@ -5741,23 +5787,30 @@
     method public boolean isReset();
     method public boolean isStarted();
     method protected void onAbandon();
+    method protected boolean onCancelLoad();
     method public void onContentChanged();
     method protected void onForceLoad();
     method protected void onReset();
     method protected void onStartLoading();
     method protected void onStopLoading();
     method public void registerListener(int, android.content.Loader.OnLoadCompleteListener<D>);
+    method public void registerOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
     method public void reset();
     method public final void startLoading();
     method public void stopLoading();
     method public boolean takeContentChanged();
     method public void unregisterListener(android.content.Loader.OnLoadCompleteListener<D>);
+    method public void unregisterOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
   }
 
   public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
     ctor public Loader.ForceLoadContentObserver();
   }
 
+  public static abstract interface Loader.OnLoadCanceledListener {
+    method public abstract void onLoadCanceled(android.content.Loader<D>);
+  }
+
   public static abstract interface Loader.OnLoadCompleteListener {
     method public abstract void onLoadComplete(android.content.Loader<D>, D);
   }
@@ -5777,6 +5830,11 @@
     method public int getNumSuccessfulYieldPoints();
   }
 
+  public class OperationCanceledException extends java.lang.RuntimeException {
+    ctor public OperationCanceledException();
+    ctor public OperationCanceledException(java.lang.String);
+  }
+
   public class PeriodicSync implements android.os.Parcelable {
     ctor public PeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long);
     method public int describeContents();
@@ -6413,6 +6471,7 @@
     method public int describeContents();
     method public void dump(android.util.Printer, java.lang.String);
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2
     field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
     field public int flags;
     field public java.lang.String permission;
@@ -6822,7 +6881,7 @@
   public abstract interface Cursor {
     method public abstract void close();
     method public abstract void copyStringToBuffer(int, android.database.CharArrayBuffer);
-    method public abstract void deactivate();
+    method public abstract deprecated void deactivate();
     method public abstract byte[] getBlob(int);
     method public abstract int getColumnCount();
     method public abstract int getColumnIndex(java.lang.String);
@@ -7221,11 +7280,15 @@
     method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
     method public android.database.Cursor query(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public android.database.Cursor query(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancellationSignal);
     method public android.database.Cursor query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String);
     method public android.database.Cursor query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
     method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancellationSignal);
     method public android.database.Cursor rawQuery(java.lang.String, java.lang.String[]);
+    method public android.database.Cursor rawQuery(java.lang.String, java.lang.String[], android.content.CancellationSignal);
     method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String, java.lang.String[], java.lang.String);
+    method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal);
     method public static int releaseMemory();
     method public long replace(java.lang.String, java.lang.String, android.content.ContentValues);
     method public long replaceOrThrow(java.lang.String, java.lang.String, android.content.ContentValues) throws android.database.SQLException;
@@ -7347,6 +7410,7 @@
     method public java.lang.String getTables();
     method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String);
     method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancellationSignal);
     method public void setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public void setDistinct(boolean);
     method public void setProjectionMap(java.util.Map<java.lang.String, java.lang.String>);
@@ -9050,14 +9114,17 @@
     ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
     method public void draw(android.graphics.Canvas);
     method public int getOpacity();
+    method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
     method public void setAlpha(int);
     method public void setColor(int);
     method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setColors(int[]);
     method public void setCornerRadii(float[]);
     method public void setCornerRadius(float);
     method public void setGradientCenter(float, float);
     method public void setGradientRadius(float);
     method public void setGradientType(int);
+    method public void setOrientation(android.graphics.drawable.GradientDrawable.Orientation);
     method public void setShape(int);
     method public void setSize(int, int);
     method public void setStroke(int, int);
@@ -10871,11 +10938,12 @@
   }
 
   public final class MediaRecorder.OutputFormat {
+    field public static final int AAC_ADTS = 6; // 0x6
     field public static final int AMR_NB = 3; // 0x3
     field public static final int AMR_WB = 4; // 0x4
     field public static final int DEFAULT = 0; // 0x0
     field public static final int MPEG_4 = 2; // 0x2
-    field public static final int RAW_AMR = 3; // 0x3
+    field public static final deprecated int RAW_AMR = 3; // 0x3
     field public static final int THREE_GPP = 1; // 0x1
   }
 
@@ -11584,7 +11652,7 @@
     method public void setNetworkPreference(int);
     method public int startUsingNetworkFeature(int, java.lang.String);
     method public int stopUsingNetworkFeature(int, java.lang.String);
-    field public static final java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+    field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
     field public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
@@ -11834,6 +11902,7 @@
     method public abstract boolean isHierarchical();
     method public boolean isOpaque();
     method public abstract boolean isRelative();
+    method public android.net.Uri normalize();
     method public static android.net.Uri parse(java.lang.String);
     method public abstract java.lang.String toString();
     method public static android.net.Uri withAppendedPath(android.net.Uri, java.lang.String);
@@ -12616,6 +12685,7 @@
     ctor public NdefMessage(android.nfc.NdefRecord, android.nfc.NdefRecord...);
     ctor public NdefMessage(android.nfc.NdefRecord[]);
     method public int describeContents();
+    method public int getByteArrayLength();
     method public android.nfc.NdefRecord[] getRecords();
     method public byte[] toByteArray();
     method public void writeToParcel(android.os.Parcel, int);
@@ -12636,6 +12706,8 @@
     method public short getTnf();
     method public byte[] getType();
     method public deprecated byte[] toByteArray();
+    method public java.lang.String toMimeType();
+    method public android.net.Uri toUri();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final byte[] RTD_ALTERNATIVE_CARRIER;
@@ -14427,6 +14499,7 @@
     field public static final int HONEYCOMB_MR2 = 13; // 0xd
     field public static final int ICE_CREAM_SANDWICH = 14; // 0xe
     field public static final int ICE_CREAM_SANDWICH_MR1 = 15; // 0xf
+    field public static final int JELLY_BEAN = 10000; // 0x2710
   }
 
   public final class Bundle implements java.lang.Cloneable android.os.Parcelable {
@@ -15108,7 +15181,7 @@
     method public static final deprecated boolean supportsProcesses();
     field public static final int BLUETOOTH_GID = 2000; // 0x7d0
     field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
-    field public static final int LAST_APPLICATION_UID = 99999; // 0x1869f
+    field public static final int LAST_APPLICATION_UID = 19999; // 0x4e1f
     field public static final int PHONE_UID = 1001; // 0x3e9
     field public static final int SIGNAL_KILL = 9; // 0x9
     field public static final int SIGNAL_QUIT = 3; // 0x3
@@ -17445,6 +17518,7 @@
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATA_ROAMING = "data_roaming";
     field public static final java.lang.String DEFAULT_INPUT_METHOD = "default_input_method";
+    field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
     field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
     field public static final java.lang.String ENABLED_ACCESSIBILITY_SERVICES = "enabled_accessibility_services";
     field public static final java.lang.String ENABLED_INPUT_METHODS = "enabled_input_methods";
@@ -17523,6 +17597,7 @@
     field public static final java.lang.String ALARM_ALERT = "alarm_alert";
     field public static final java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
+    field public static final java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
     field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final java.lang.String AUTO_TIME = "auto_time";
     field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
@@ -20404,6 +20479,19 @@
     method public int getTopPadding();
   }
 
+  public abstract interface TextDirectionHeuristic {
+  }
+
+  public class TextDirectionHeuristics {
+    ctor public TextDirectionHeuristics();
+    field public static final android.text.TextDirectionHeuristic ANYRTL_LTR;
+    field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_LTR;
+    field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_RTL;
+    field public static final android.text.TextDirectionHeuristic LOCALE;
+    field public static final android.text.TextDirectionHeuristic LTR;
+    field public static final android.text.TextDirectionHeuristic RTL;
+  }
+
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -21391,6 +21479,7 @@
     field public static final int DENSITY_MEDIUM = 160; // 0xa0
     field public static final int DENSITY_TV = 213; // 0xd5
     field public static final int DENSITY_XHIGH = 320; // 0x140
+    field public static final int DENSITY_XXHIGH = 480; // 0x1e0
     field public float density;
     field public int densityDpi;
     field public int heightPixels;
@@ -21525,6 +21614,26 @@
     method public void println(java.lang.String);
   }
 
+  public class LongSparseArray implements java.lang.Cloneable {
+    ctor public LongSparseArray();
+    ctor public LongSparseArray(int);
+    method public void append(long, E);
+    method public void clear();
+    method public android.util.LongSparseArray<E> clone();
+    method public void delete(long);
+    method public E get(long);
+    method public E get(long, E);
+    method public int indexOfKey(long);
+    method public int indexOfValue(E);
+    method public long keyAt(int);
+    method public void put(long, E);
+    method public void remove(long);
+    method public void removeAt(int);
+    method public void setValueAt(int, E);
+    method public int size();
+    method public E valueAt(int);
+  }
+
   public class LruCache {
     ctor public LruCache(int);
     method protected V create(K);
@@ -23076,6 +23185,7 @@
     method public final android.view.ViewParent getParent();
     method public float getPivotX();
     method public float getPivotY();
+    method public int getResolvedTextDirection();
     method public android.content.res.Resources getResources();
     method public final int getRight();
     method protected float getRightFadingEdgeStrength();
@@ -23095,6 +23205,7 @@
     method public int getSystemUiVisibility();
     method public java.lang.Object getTag();
     method public java.lang.Object getTag(int);
+    method public int getTextDirection();
     method public final int getTop();
     method protected float getTopFadingEdgeStrength();
     method protected int getTopPaddingOffset();
@@ -23226,8 +23337,10 @@
     method public void requestLayout();
     method public boolean requestRectangleOnScreen(android.graphics.Rect);
     method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
+    method protected void resetResolvedTextDirection();
     method public static int resolveSize(int, int);
     method public static int resolveSizeAndState(int, int, int);
+    method protected void resolveTextDirection();
     method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
@@ -23307,6 +23420,7 @@
     method public void setSystemUiVisibility(int);
     method public void setTag(java.lang.Object);
     method public void setTag(int, java.lang.Object);
+    method public void setTextDirection(int);
     method public final void setTop(int);
     method public void setTouchDelegate(android.view.TouchDelegate);
     method public void setTranslationX(float);
@@ -23329,6 +23443,7 @@
     method public boolean willNotCacheDrawing();
     method public boolean willNotDraw();
     field public static final android.util.Property ALPHA;
+    field protected static int DEFAULT_TEXT_DIRECTION;
     field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0
     field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000
     field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000
@@ -23405,6 +23520,12 @@
     field public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2; // 0x2
     field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
+    field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2
+    field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1
+    field public static final int TEXT_DIRECTION_INHERIT = 0; // 0x0
+    field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5
+    field public static final int TEXT_DIRECTION_LTR = 3; // 0x3
+    field public static final int TEXT_DIRECTION_RTL = 4; // 0x4
     field public static final android.util.Property TRANSLATION_X;
     field public static final android.util.Property TRANSLATION_Y;
     field protected static final java.lang.String VIEW_LOG_TAG = "View";
@@ -23671,7 +23792,6 @@
     method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public void requestTransparentRegion(android.view.View);
     method protected void resetResolvedLayoutDirection();
-    method protected void resetResolvedTextDirection();
     method public void scheduleLayoutAnimation();
     method public void setAddStatesFromChildren(boolean);
     method public void setAlwaysDrawnWithCacheEnabled(boolean);
@@ -23789,6 +23909,9 @@
     method public android.view.ViewPropertyAnimator translationXBy(float);
     method public android.view.ViewPropertyAnimator translationY(float);
     method public android.view.ViewPropertyAnimator translationYBy(float);
+    method public android.view.ViewPropertyAnimator withEndAction(java.lang.Runnable);
+    method public android.view.ViewPropertyAnimator withLayer();
+    method public android.view.ViewPropertyAnimator withStartAction(java.lang.Runnable);
     method public android.view.ViewPropertyAnimator x(float);
     method public android.view.ViewPropertyAnimator xBy(float);
     method public android.view.ViewPropertyAnimator y(float);
@@ -24814,6 +24937,7 @@
     method public void showSoftInputFromInputMethod(android.os.IBinder, int);
     method public void showStatusIcon(android.os.IBinder, java.lang.String, int);
     method public boolean switchToLastInputMethod(android.os.IBinder);
+    method public boolean switchToNextInputMethod(android.os.IBinder, boolean);
     method public void toggleSoftInput(int, int);
     method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
     method public void updateCursor(android.view.View, int, int, int, int);
@@ -26308,10 +26432,12 @@
     field public static final android.widget.GridLayout.Alignment BASELINE;
     field public static final android.widget.GridLayout.Alignment BOTTOM;
     field public static final android.widget.GridLayout.Alignment CENTER;
+    field public static final android.widget.GridLayout.Alignment END;
     field public static final android.widget.GridLayout.Alignment FILL;
     field public static final int HORIZONTAL = 0; // 0x0
     field public static final android.widget.GridLayout.Alignment LEFT;
     field public static final android.widget.GridLayout.Alignment RIGHT;
+    field public static final android.widget.GridLayout.Alignment START;
     field public static final android.widget.GridLayout.Alignment TOP;
     field public static final int UNDEFINED = -2147483648; // 0x80000000
     field public static final int VERTICAL = 1; // 0x1
@@ -26676,6 +26802,7 @@
     method public void setOnValueChangedListener(android.widget.NumberPicker.OnValueChangeListener);
     method public void setValue(int);
     method public void setWrapSelectorWheel(boolean);
+    field public static final int SELECTOR_WHEEL_ITEM_COUNT = 5; // 0x5
   }
 
   public static abstract interface NumberPicker.Formatter {
@@ -27493,7 +27620,6 @@
     method protected void resetResolvedDrawables();
     method protected void resetResolvedLayoutDirection();
     method protected void resolveDrawables();
-    method protected void resolveTextDirection();
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
     method public void setCompoundDrawablePadding(int);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index fddb429..901f7c7 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -31,6 +31,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -135,6 +136,8 @@
             runToUri(false);
         } else if (op.equals("to-intent-uri")) {
             runToUri(true);
+        } else if (op.equals("switch-profile")) {
+            runSwitchUser();
         } else {
             throw new IllegalArgumentException("Unknown command: " + op);
         }
@@ -212,6 +215,22 @@
                     list[i] = Long.valueOf(strings[i]);
                 }
                 intent.putExtra(key, list);
+                hasIntentInfo = true;
+            } else if (opt.equals("--ef")) {
+                String key = nextArgRequired();
+                String value = nextArgRequired();
+                intent.putExtra(key, Float.valueOf(value));
+                hasIntentInfo = true;
+            } else if (opt.equals("--efa")) {
+                String key = nextArgRequired();
+                String value = nextArgRequired();
+                String[] strings = value.split(",");
+                float[] list = new float[strings.length];
+                for (int i = 0; i < strings.length; i++) {
+                    list[i] = Float.valueOf(strings[i]);
+                }
+                intent.putExtra(key, list);
+                hasIntentInfo = true;
             } else if (opt.equals("--ez")) {
                 String key = nextArgRequired();
                 String value = nextArgRequired();
@@ -531,7 +550,8 @@
         Intent intent = makeIntent();
         IntentReceiver receiver = new IntentReceiver();
         System.out.println("Broadcasting: " + intent);
-        mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false);
+        mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false,
+                Binder.getOrigCallingUser());
         receiver.waitForFinish();
     }
 
@@ -722,6 +742,14 @@
         mAm.setDebugApp(null, false, true);
     }
 
+    private void runSwitchUser() throws Exception {
+        if (android.os.Process.myUid() != 0) {
+            throw new RuntimeException("switchuser can only be run as root");
+        }
+        String user = nextArgRequired();
+        mAm.switchUser(Integer.parseInt(user));
+    }
+
     class MyActivityController extends IActivityController.Stub {
         final String mGdbPort;
 
@@ -1330,9 +1358,11 @@
                 "    [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
                 "    [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
                 "    [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
+                "    [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" +
                 "    [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
                 "    [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
                 "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
+                "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
                 "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
                 "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
                 "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 83c881a..16dc517 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -122,7 +122,7 @@
     dump_file("NETWORK DEV INFO", "/proc/net/dev");
     dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
     dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
-    run_command("QTAGUID STATS INFO", 10, "su", "root", "cat", "/proc/net/xt_qtaguid/stats", NULL);
+    dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
 
     dump_file("NETWORK ROUTES", "/proc/net/route");
     dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route");
@@ -334,7 +334,7 @@
         }
 
         /* switch to non-root user and group */
-        gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT, AID_INET };
+        gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT, AID_INET, AID_NET_BW_STATS };
         if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
             ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
             return -1;
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index dd92bbe..203d180 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -148,6 +148,48 @@
     return delete_dir_contents(pkgdir, 1, NULL);
 }
 
+int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
+{
+    char src_data_dir[PKG_PATH_MAX];
+    char pkg_path[PKG_PATH_MAX];
+    DIR *d;
+    struct dirent *de;
+    struct stat s;
+    uid_t uid;
+
+    if (create_persona_path(src_data_dir, src_persona)) {
+        return -1;
+    }
+
+    d = opendir(src_data_dir);
+    if (d != NULL) {
+        while ((de = readdir(d))) {
+            const char *name = de->d_name;
+
+            if (de->d_type == DT_DIR) {
+                int subfd;
+                    /* always skip "." and ".." */
+                if (name[0] == '.') {
+                    if (name[1] == 0) continue;
+                    if ((name[1] == '.') && (name[2] == 0)) continue;
+                }
+                /* Create the full path to the package's data dir */
+                create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
+                /* Get the file stat */
+                if (stat(pkg_path, &s) < 0) continue;
+                /* Get the uid of the package */
+                ALOGI("Adding datadir for uid = %d\n", s.st_uid);
+                uid = (uid_t) s.st_uid % PER_USER_RANGE;
+                /* Create the directory for the target */
+                make_user_data(name, uid + target_persona * PER_USER_RANGE,
+                               target_persona);
+            }
+        }
+        closedir(d);
+    }
+    return 0;
+}
+
 int delete_cache(const char *pkgname)
 {
     char cachedir[PKG_PATH_MAX];
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 569b491..7f94a96 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -107,6 +107,11 @@
     return delete_persona(atoi(arg[0])); /* userid */
 }
 
+static int do_clone_user_data(char **arg, char reply[REPLY_MAX])
+{
+    return clone_persona_data(atoi(arg[0]), atoi(arg[1]), atoi(arg[2]));
+}
+
 static int do_movefiles(char **arg, char reply[REPLY_MAX])
 {
     return movefiles();
@@ -146,6 +151,7 @@
     { "unlinklib",            1, do_unlinklib },
     { "mkuserdata",           3, do_mk_user_data },
     { "rmuser",               1, do_rm_user },
+    { "cloneuserdata",        3, do_clone_user_data },
 };
 
 static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 173cabf..78342bb 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -72,6 +72,9 @@
 #define PKG_NAME_MAX  128   /* largest allowed package name */
 #define PKG_PATH_MAX  256   /* max size of any path we use */
 
+#define PER_USER_RANGE ((uid_t)100000)   /* range of uids per user
+                                            uid = persona * PER_USER_RANGE + appid */
+
 /* data structures */
 
 typedef struct {
@@ -143,6 +146,7 @@
 int delete_user_data(const char *pkgname, uid_t persona);
 int make_user_data(const char *pkgname, uid_t uid, uid_t persona);
 int delete_persona(uid_t persona);
+int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy);
 int delete_cache(const char *pkgname);
 int move_dex(const char *src, const char *dst);
 int rm_dex(const char *path);
diff --git a/cmds/keystore/keystore.cpp b/cmds/keystore/keystore.cpp
index 05f77e5..2c9cb35 100644
--- a/cmds/keystore/keystore.cpp
+++ b/cmds/keystore/keystore.cpp
@@ -581,7 +581,7 @@
 static ResponseCode insert(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* val) {
     char filename[NAME_MAX];
     encode_key(filename, uid, keyName);
-    Blob keyBlob(val->value, val->length, 0, NULL);
+    Blob keyBlob(val->value, val->length, NULL, 0);
     return keyStore->put(filename, &keyBlob);
 }
 
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index c0ba543..f457842 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -16,8 +16,6 @@
 
 package com.android.commands.pm;
 
-import com.android.internal.content.PackageHelper;
-
 import android.app.ActivityManagerNative;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
@@ -33,14 +31,17 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
+import android.content.pm.UserInfo;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
-import android.os.Parcel;
+import android.os.Binder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 
+import com.android.internal.content.PackageHelper;
+
 import java.io.File;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -135,13 +136,18 @@
             return;
         }
 
-        if ("createUser".equals(op)) {
-            runCreateUser();
+        if ("create-profile".equals(op)) {
+            runCreateProfile();
             return;
         }
 
-        if ("removeUser".equals(op)) {
-            runRemoveUser();
+        if ("remove-profile".equals(op)) {
+            runRemoveProfile();
+            return;
+        }
+
+        if ("list-profiles".equals(op)) {
+            runListProfiles();
             return;
         }
 
@@ -829,10 +835,10 @@
         }
     }
 
-    public void runCreateUser() {
+    public void runCreateProfile() {
         // Need to be run as root
         if (Process.myUid() != ROOT_UID) {
-            System.err.println("Error: createUser must be run as root");
+            System.err.println("Error: create-profile must be run as root");
             return;
         }
         String name;
@@ -845,7 +851,7 @@
         name = arg;
         try {
             if (mPm.createUser(name, 0) == null) {
-                System.err.println("Error: couldn't create user.");
+                System.err.println("Error: couldn't create profile.");
                 showUsage();
             }
         } catch (RemoteException e) {
@@ -855,10 +861,10 @@
 
     }
 
-    public void runRemoveUser() {
+    public void runRemoveProfile() {
         // Need to be run as root
         if (Process.myUid() != ROOT_UID) {
-            System.err.println("Error: removeUser must be run as root");
+            System.err.println("Error: remove-profile must be run as root");
             return;
         }
         int userId;
@@ -877,7 +883,7 @@
         }
         try {
             if (!mPm.removeUser(userId)) {
-                System.err.println("Error: couldn't remove user.");
+                System.err.println("Error: couldn't remove profile.");
                 showUsage();
             }
         } catch (RemoteException e) {
@@ -886,6 +892,27 @@
         }
     }
 
+    public void runListProfiles() {
+        // Need to be run as root
+        if (Process.myUid() != ROOT_UID) {
+            System.err.println("Error: list-profiles must be run as root");
+            return;
+        }
+        try {
+            List<UserInfo> users = mPm.getUsers();
+            if (users == null) {
+                System.err.println("Error: couldn't get users");
+            } else {
+                System.out.println("Users:");
+                for (int i = 0; i < users.size(); i++) {
+                    System.out.println("\t" + users.get(i).toString());
+                }
+            }
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(PM_NOT_RUNNING_ERR);
+        }
+    }
     class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
         boolean finished;
         boolean result;
@@ -966,7 +993,8 @@
 
         ClearDataObserver obs = new ClearDataObserver();
         try {
-            if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs)) {
+            if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs,
+                    Binder.getOrigCallingUser())) {
                 System.err.println("Failed");
             }
 
@@ -1132,8 +1160,8 @@
         System.err.println("       pm disable-user PACKAGE_OR_COMPONENT");
         System.err.println("       pm set-install-location [0/auto] [1/internal] [2/external]");
         System.err.println("       pm get-install-location");
-        System.err.println("       pm createUser USER_NAME");
-        System.err.println("       pm removeUser USER_ID");
+        System.err.println("       pm create-profile USER_NAME");
+        System.err.println("       pm remove-profile USER_ID");
         System.err.println("");
         System.err.println("pm list packages: prints all packages, optionally only");
         System.err.println("  those whose package name contains the text in FILTER.  Options:");
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 7a599e9..bee5880 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -28,6 +28,7 @@
 
 #include <SkImageEncoder.h>
 #include <SkBitmap.h>
+#include <SkData.h>
 #include <SkStream.h>
 
 using namespace android;
@@ -168,7 +169,9 @@
             SkDynamicMemoryWStream stream;
             SkImageEncoder::EncodeStream(&stream, b,
                     SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
-            write(fd, stream.getStream(), stream.getOffset());
+            SkData* streamData = stream.copyToData();
+            write(fd, streamData->data(), streamData->size());
+            streamData->unref();
         } else {
             write(fd, &w, 4);
             write(fd, &h, 4);
diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk
index ea80c7d..8840867 100644
--- a/cmds/servicemanager/Android.mk
+++ b/cmds/servicemanager/Android.mk
@@ -9,7 +9,4 @@
 LOCAL_SHARED_LIBRARIES := liblog
 LOCAL_SRC_FILES := service_manager.c binder.c
 LOCAL_MODULE := servicemanager
-ifeq ($(BOARD_USE_LVMX),true)
-    LOCAL_CFLAGS += -DLVMX
-endif
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 42d8977..cfc2d16 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -27,9 +27,6 @@
     unsigned uid;
     const char *name;
 } allowed[] = {
-#ifdef LVMX
-    { AID_MEDIA, "com.lifevibes.mx.ipc" },
-#endif
     { AID_MEDIA, "media.audio_flinger" },
     { AID_MEDIA, "media.player" },
     { AID_MEDIA, "media.camera" },
@@ -93,6 +90,7 @@
     struct svcinfo *next;
     void *ptr;
     struct binder_death death;
+    int allow_isolated;
     unsigned len;
     uint16_t name[0];
 };
@@ -128,13 +126,21 @@
 };
   
 
-void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)
+void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid)
 {
     struct svcinfo *si;
     si = find_svc(s, len);
 
 //    ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
     if (si && si->ptr) {
+        if (!si->allow_isolated) {
+            // If this service doesn't allow access from isolated processes,
+            // then check the uid to see if it is isolated.
+            unsigned appid = uid % AID_USER;
+            if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
+                return 0;
+            }
+        }
         return si->ptr;
     } else {
         return 0;
@@ -143,10 +149,11 @@
 
 int do_add_service(struct binder_state *bs,
                    uint16_t *s, unsigned len,
-                   void *ptr, unsigned uid)
+                   void *ptr, unsigned uid, int allow_isolated)
 {
     struct svcinfo *si;
-//    ALOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid);
+    //ALOGI("add_service('%s',%p,%s) uid=%d\n", str8(s), ptr,
+    //        allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
 
     if (!ptr || (len == 0) || (len > 127))
         return -1;
@@ -178,6 +185,7 @@
         si->name[len] = '\0';
         si->death.func = svcinfo_death;
         si->death.ptr = si;
+        si->allow_isolated = allow_isolated;
         si->next = svclist;
         svclist = si;
     }
@@ -197,6 +205,7 @@
     unsigned len;
     void *ptr;
     uint32_t strict_policy;
+    int allow_isolated;
 
 //    ALOGI("target=%p code=%d pid=%d uid=%d\n",
 //         txn->target, txn->code, txn->sender_pid, txn->sender_euid);
@@ -220,7 +229,7 @@
     case SVC_MGR_GET_SERVICE:
     case SVC_MGR_CHECK_SERVICE:
         s = bio_get_string16(msg, &len);
-        ptr = do_find_service(bs, s, len);
+        ptr = do_find_service(bs, s, len, txn->sender_euid);
         if (!ptr)
             break;
         bio_put_ref(reply, ptr);
@@ -229,7 +238,8 @@
     case SVC_MGR_ADD_SERVICE:
         s = bio_get_string16(msg, &len);
         ptr = bio_get_ref(msg);
-        if (do_add_service(bs, s, len, ptr, txn->sender_euid))
+        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
+        if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
             return -1;
         break;
 
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index e9642f7..11e94e8 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -35,7 +35,7 @@
         record.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder
+	libstagefright liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
@@ -59,7 +59,7 @@
         recordvideo.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder
+	libstagefright liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
@@ -84,7 +84,7 @@
         audioloop.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder
+	libstagefright liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 021f636..14b4306 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -3,7 +3,7 @@
 #include <math.h>
 
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index 858681f..a6362a4 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -2,10 +2,10 @@
 
 #include <binder/ProcessState.h>
 #include <media/mediarecorder.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/AudioSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXClient.h>
@@ -24,7 +24,7 @@
     android::ProcessState::self()->startThreadPool();
 
     OMXClient client;
-    CHECK_EQ(client.connect(), OK);
+    CHECK_EQ(client.connect(), (status_t)OK);
 
 #if 0
     sp<MediaSource> source = new SineSource(kSampleRate, kNumChannels);
@@ -82,7 +82,7 @@
     delete player;
     player = NULL;
 #elif 0
-    CHECK_EQ(decoder->start(), OK);
+    CHECK_EQ(decoder->start(), (status_t)OK);
 
     MediaBuffer *buffer;
     while (decoder->read(&buffer) == OK) {
@@ -95,7 +95,7 @@
         buffer = NULL;
     }
 
-    CHECK_EQ(decoder->stop(), OK);
+    CHECK_EQ(decoder->stop(), (status_t)OK);
 #endif
 #endif
 
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 613435d..45c3f7b 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,11 +17,11 @@
 #include "SineSource.h"
 
 #include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaExtractor.h>
@@ -38,7 +38,7 @@
 static const int32_t kAudioBitRate = 12200;
 static const int64_t kDurationUs = 10000000LL;  // 10 seconds
 
-#if 1
+#if 0
 class DummySource : public MediaSource {
 
 public:
@@ -183,7 +183,7 @@
         return 1;
     }
     OMXClient client;
-    CHECK_EQ(client.connect(), OK);
+    CHECK_EQ(client.connect(), (status_t)OK);
 
     status_t err = OK;
 
@@ -231,14 +231,14 @@
     sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
     writer->addSource(encoder);
     writer->setMaxFileDuration(kDurationUs);
-    CHECK_EQ(OK, writer->start());
+    CHECK_EQ((status_t)OK, writer->start());
     while (!writer->reachedEOS()) {
         fprintf(stderr, ".");
         usleep(100000);
     }
     err = writer->stop();
 #else
-    CHECK_EQ(OK, encoder->start());
+    CHECK_EQ((status_t)OK, encoder->start());
 
     MediaBuffer *buffer;
     while (encoder->read(&buffer) == OK) {
@@ -272,7 +272,7 @@
     for (int i = 0; i < 100; ++i) {
         MediaBuffer *buffer;
         status_t err = source->read(&buffer);
-        CHECK_EQ(err, OK);
+        CHECK_EQ(err, (status_t)OK);
 
         printf("got a frame, data=%p, size=%d\n",
                buffer->data(), buffer->range_length());
@@ -299,7 +299,7 @@
     android::ProcessState::self()->startThreadPool();
 
     OMXClient client;
-    CHECK_EQ(client.connect(), OK);
+    CHECK_EQ(client.connect(), (status_t)OK);
 
     const int32_t kSampleRate = 22050;
     const int32_t kNumChannels = 2;
@@ -318,7 +318,7 @@
 
     sp<MetaData> encMeta = new MetaData;
     encMeta->setCString(kKeyMIMEType,
-            1 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC);
+            0 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC);
     encMeta->setInt32(kKeySampleRate, kSampleRate);
     encMeta->setInt32(kKeyChannelCount, kNumChannels);
     encMeta->setInt32(kKeyMaxInputSize, 8192);
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index c402286..3bd1fe2 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -17,9 +17,9 @@
 #include "SineSource.h"
 
 #include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MPEG4Writer.h>
@@ -243,7 +243,7 @@
     }
 
     OMXClient client;
-    CHECK_EQ(client.connect(), OK);
+    CHECK_EQ(client.connect(), (status_t)OK);
 
     status_t err = OK;
     sp<MediaSource> source =
@@ -283,7 +283,7 @@
     sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
     writer->addSource(encoder);
     int64_t start = systemTime();
-    CHECK_EQ(OK, writer->start());
+    CHECK_EQ((status_t)OK, writer->start());
     while (!writer->reachedEOS()) {
     }
     err = writer->stop();
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp
index 78b1007..6dbcf5c 100644
--- a/cmds/surfaceflinger/main_surfaceflinger.cpp
+++ b/cmds/surfaceflinger/main_surfaceflinger.cpp
@@ -20,6 +20,6 @@
 using namespace android;
 
 int main(int argc, char** argv) {
-    SurfaceFlinger::publishAndJoinThreadPool();
+    SurfaceFlinger::publishAndJoinThreadPool(true);
     return 0;
 }
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 211be52..a463a62 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -17,8 +17,10 @@
 package android.accessibilityservice;
 
 import android.app.Service;
+import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
@@ -218,10 +220,17 @@
 
     private static final String LOG_TAG = "AccessibilityService";
 
-    private AccessibilityServiceInfo mInfo;
+    interface Callbacks {
+        public void onAccessibilityEvent(AccessibilityEvent event);
+        public void onInterrupt();
+        public void onServiceConnected();
+        public void onSetConnectionId(int connectionId);
+    }
 
     private int mConnectionId;
 
+    private AccessibilityServiceInfo mInfo;
+
     /**
      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
      *
@@ -282,27 +291,49 @@
      */
     @Override
     public final IBinder onBind(Intent intent) {
-        return new IEventListenerWrapper(this);
+        return new IEventListenerWrapper(this, getMainLooper(), new Callbacks() {
+            @Override
+            public void onServiceConnected() {
+                AccessibilityService.this.onServiceConnected();
+            }
+
+            @Override
+            public void onInterrupt() {
+                AccessibilityService.this.onInterrupt();
+            }
+
+            @Override
+            public void onAccessibilityEvent(AccessibilityEvent event) {
+                AccessibilityService.this.onAccessibilityEvent(event);
+            }
+
+            @Override
+            public void onSetConnectionId( int connectionId) {
+                mConnectionId = connectionId;
+            }
+        });
     }
 
     /**
      * Implements the internal {@link IEventListener} interface to convert
      * incoming calls to it back to calls on an {@link AccessibilityService}.
      */
-    class IEventListenerWrapper extends IEventListener.Stub
+    static class IEventListenerWrapper extends IEventListener.Stub
             implements HandlerCaller.Callback {
 
+        static final int NO_ID = -1;
+
         private static final int DO_SET_SET_CONNECTION = 10;
         private static final int DO_ON_INTERRUPT = 20;
         private static final int DO_ON_ACCESSIBILITY_EVENT = 30;
 
         private final HandlerCaller mCaller;
 
-        private final AccessibilityService mTarget;
+        private final Callbacks mCallback;
 
-        public IEventListenerWrapper(AccessibilityService context) {
-            mTarget = context;
-            mCaller = new HandlerCaller(context, this);
+        public IEventListenerWrapper(Context context, Looper looper, Callbacks callback) {
+            mCallback = callback;
+            mCaller = new HandlerCaller(context, looper, this);
         }
 
         public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
@@ -326,12 +357,13 @@
                 case DO_ON_ACCESSIBILITY_EVENT :
                     AccessibilityEvent event = (AccessibilityEvent) message.obj;
                     if (event != null) {
-                        mTarget.onAccessibilityEvent(event);
+                        AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
+                        mCallback.onAccessibilityEvent(event);
                         event.recycle();
                     }
                     return;
                 case DO_ON_INTERRUPT :
-                    mTarget.onInterrupt();
+                    mCallback.onInterrupt();
                     return;
                 case DO_SET_SET_CONNECTION :
                     final int connectionId = message.arg1;
@@ -340,12 +372,11 @@
                     if (connection != null) {
                         AccessibilityInteractionClient.getInstance().addConnection(connectionId,
                                 connection);
-                        mConnectionId = connectionId;
-                        mTarget.onServiceConnected();
+                        mCallback.onSetConnectionId(connectionId);
+                        mCallback.onServiceConnected();
                     } else {
                         AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
-                        mConnectionId = AccessibilityInteractionClient.NO_ID;
-                        // TODO: Do we need a onServiceDisconnected callback?
+                        mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
                     }
                     return;
                 default :
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index e53b313..c9468eb 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -32,8 +32,13 @@
     /**
      * Finds an {@link AccessibilityNodeInfo} by accessibility id.
      *
-     * @param accessibilityWindowId A unique window id.
-     * @param accessibilityNodeId A unique view id or virtual descendant id.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
      * @param threadId The id of the calling thread.
@@ -46,57 +51,58 @@
     /**
      * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
      * insensitive containment. The search is performed in the window whose
-     * id is specified and starts from the View whose accessibility id is
+     * id is specified and starts from the node whose accessibility id is
      * specified.
      *
-     * @param text The searched text.
-     * @param accessibilityWindowId A unique window id.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
-     *        where to start the search. Use {@link android.view.View#NO_ID} to start from the root.
-     * @param interactionId The id of the interaction for matching with the callback result.
-     * @param callback Callback which to receive the result.
-     * @param threadId The id of the calling thread.
-     * @return The current window scale, where zero means a failure.
-     */
-    float findAccessibilityNodeInfosByText(String text, int accessibilityWindowId,
-        long accessibilityNodeId, int interractionId,
-        IAccessibilityInteractionConnectionCallback callback, long threadId);
-
-    /**
-     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
-     * insensitive containment. The search is performed in the currently
-     * active window and start from the root View in the window.
-     *
+     *     where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param text The searched text.
-     * @param accessibilityId The id of the view from which to start searching.
-     *        Use {@link android.view.View#NO_ID} to start from the root.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
      * @param threadId The id of the calling thread.
      * @return The current window scale, where zero means a failure.
      */
-    float findAccessibilityNodeInfosByTextInActiveWindow(String text,
-        int interactionId, IAccessibilityInteractionConnectionCallback callback,
+    float findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
+        String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
         long threadId);
 
     /**
-     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
-     * in the currently active window and starts from the root View in the window.
+     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+     * the window whose id is specified and starts from the node whose accessibility
+     * id is specified.
      *
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param id The id of the node.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
      * @param threadId The id of the calling thread.
      * @return The current window scale, where zero means a failure.
      */
-    float findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId, int interactionId,
-        IAccessibilityInteractionConnectionCallback callback, long threadId);
+    float findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId,
+        int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+        long threadId);
 
     /**
      * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
      *
-     * @param accessibilityWindowId The id of the window.
-     * @param accessibilityNodeId A unique view id or virtual descendant id.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param action The action to perform.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
diff --git a/core/java/android/accessibilityservice/UiTestAutomationBridge.java b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
new file mode 100644
index 0000000..616b796
--- /dev/null
+++ b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice;
+
+import android.accessibilityservice.AccessibilityService.Callbacks;
+import android.accessibilityservice.AccessibilityService.IEventListenerWrapper;
+import android.content.Context;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityInteractionClient;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityManager;
+
+import com.android.internal.util.Predicate;
+
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This class represents a bridge that can be used for UI test
+ * automation. It is responsible for connecting to the system,
+ * keeping track of the last accessibility event, and exposing
+ * window content querying APIs. This class is designed to be
+ * used from both an Android application and a Java program
+ * run from the shell.
+ *
+ * @hide
+ */
+public class UiTestAutomationBridge {
+
+    private static final String LOG_TAG = UiTestAutomationBridge.class.getSimpleName();
+
+    public static final int ACTIVE_WINDOW_ID = -1;
+
+    public static final long ROOT_NODE_ID = -1;
+
+    private static final int TIMEOUT_REGISTER_SERVICE = 5000;
+
+    private final Object mLock = new Object();
+
+    private volatile int mConnectionId = AccessibilityInteractionClient.NO_ID;
+
+    private IEventListenerWrapper mListener;
+
+    private AccessibilityEvent mLastEvent;
+
+    private AccessibilityEvent mLastWindowStateChangeEvent;
+
+    private volatile boolean mWaitingForEventDelivery;
+
+    private volatile boolean mUnprocessedEventAvailable;
+
+    /**
+     * Gets the last received {@link AccessibilityEvent}.
+     *
+     * @return The event.
+     */
+    public AccessibilityEvent getLastAccessibilityEvent() {
+        return mLastEvent; 
+    }
+
+    /**
+     * Callback for receiving an {@link AccessibilityEvent}.
+     *
+     * <strong>Note:</strong> This method is <strong>NOT</strong>
+     * executed on the application main thread. The client are
+     * responsible for proper synchronization.
+     *
+     * @param event The received event.
+     */
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        /* hook - do nothing */
+    }
+
+    /**
+     * Callback for requests to stop feedback.
+     *
+     * <strong>Note:</strong> This method is <strong>NOT</strong>
+     * executed on the application main thread. The client are
+     * responsible for proper synchronization.
+     */
+    public void onInterrupt() {
+        /* hook - do nothing */
+    }
+
+    /**
+     * Connects this service.
+     *
+     * @throws IllegalStateException If already connected.
+     */
+    public void connect() {
+        if (isConnected()) {
+            throw new IllegalStateException("Already connected.");
+        }
+
+        // Serialize binder calls to a handler on a dedicated thread
+        // different from the main since we expose APIs that block
+        // the main thread waiting for a result the deliver of which
+        // on the main thread will prevent that thread from waking up.
+        // The serialization is needed also to ensure that events are
+        // examined in delivery order. Otherwise, a fair locking
+        // is needed for making sure the binder calls are interleaved
+        // with check for the expected event and also to make sure the
+        // binder threads are allowed to proceed in the received order.
+        HandlerThread handlerThread = new HandlerThread("UiTestAutomationBridge");
+        handlerThread.start();
+        Looper looper = handlerThread.getLooper();
+
+        mListener = new IEventListenerWrapper(null, looper, new Callbacks() {
+            @Override
+            public void onServiceConnected() {
+                /* do nothing */
+            }
+
+            @Override
+            public void onInterrupt() {
+                UiTestAutomationBridge.this.onInterrupt();  
+            }
+
+            @Override
+            public void onAccessibilityEvent(AccessibilityEvent event) {
+                synchronized (mLock) {
+                    while (true) {
+                        mLastEvent = AccessibilityEvent.obtain(event);
+
+                        final int eventType = event.getEventType();
+                        if (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+                                || eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
+                            if (mLastWindowStateChangeEvent != null) {
+                                mLastWindowStateChangeEvent.recycle();
+                            }
+                            mLastWindowStateChangeEvent = mLastEvent;
+                        }
+
+                        if (!mWaitingForEventDelivery) {
+                            break;
+                        }
+                        if (!mUnprocessedEventAvailable) {
+                            mUnprocessedEventAvailable = true;
+                            mLock.notifyAll();
+                            break;
+                        }
+                        try {
+                            mLock.wait();
+                        } catch (InterruptedException ie) {
+                            /* ignore */
+                        }
+                    }
+                }
+                UiTestAutomationBridge.this.onAccessibilityEvent(event);
+            }
+
+            @Override
+            public void onSetConnectionId(int connectionId) {
+                synchronized (mLock) {
+                    mConnectionId = connectionId;
+                    mLock.notifyAll();
+                }
+            }
+        });
+
+        final IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+                ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+
+        final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+        info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
+        info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
+
+        try {
+            manager.registerUiTestAutomationService(mListener, info);
+        } catch (RemoteException re) {
+            throw new IllegalStateException("Cound not register UiAutomationService.", re);
+        }
+
+        synchronized (mLock) {
+            final long startTimeMillis = SystemClock.uptimeMillis();
+            while (true) {
+                if (isConnected()) {
+                    return;
+                }
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                final long remainingTimeMillis = TIMEOUT_REGISTER_SERVICE - elapsedTimeMillis;
+                if (remainingTimeMillis <= 0) {
+                    throw new IllegalStateException("Cound not register UiAutomationService.");
+                }
+                try {
+                    mLock.wait(remainingTimeMillis);
+                } catch (InterruptedException ie) {
+                    /* ignore */
+                }
+            }
+        }
+    }
+
+    /**
+     * Disconnects this service.
+     *
+     * @throws IllegalStateException If already disconnected.
+     */
+    public void disconnect() {
+        if (!isConnected()) {
+            throw new IllegalStateException("Already disconnected.");
+        }
+
+        IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+              ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+
+        try {
+            manager.unregisterUiTestAutomationService(mListener);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error while unregistering UiTestAutomationService", re);
+        }
+    }
+
+    /**
+     * Gets whether this service is connected.
+     *
+     * @return True if connected.
+     */
+    public boolean isConnected() {
+        return (mConnectionId != AccessibilityInteractionClient.NO_ID);
+    }
+
+    /**
+     * Executes a command and waits for a specific accessibility event type up
+     * to a given timeout.
+     *
+     * @param command The command to execute before starting to wait for the event.
+     * @param predicate Predicate for recognizing the awaited event.
+     * @param timeoutMillis The max wait time in milliseconds.
+     */
+    public AccessibilityEvent executeCommandAndWaitForAccessibilityEvent(Runnable command,
+            Predicate<AccessibilityEvent> predicate, long timeoutMillis)
+            throws TimeoutException, Exception {
+        synchronized (mLock) {
+            // Prepare to wait for an event.
+            mWaitingForEventDelivery = true;
+            mUnprocessedEventAvailable = false;
+            if (mLastEvent != null) {
+                mLastEvent.recycle();
+                mLastEvent = null;
+            }
+            // Execute the command.
+            command.run();
+            // Wait for the event.
+            final long startTimeMillis = SystemClock.uptimeMillis();
+            while (true) {
+                // If the expected event is received, that's it.
+                if ((mUnprocessedEventAvailable && predicate.apply(mLastEvent))) {
+                    mWaitingForEventDelivery = false;
+                    mUnprocessedEventAvailable = false;
+                    mLock.notifyAll();
+                    return mLastEvent;
+                }
+                // Ask for another event.
+                mWaitingForEventDelivery = true;
+                mUnprocessedEventAvailable = false;
+                mLock.notifyAll();
+                // Check if timed out and if not wait.
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
+                if (remainingTimeMillis <= 0) {
+                    mWaitingForEventDelivery = false;
+                    mUnprocessedEventAvailable = false;
+                    mLock.notifyAll();
+                    throw new TimeoutException("Expacted event not received within: "
+                            + timeoutMillis + " ms.");
+                }
+                try {
+                    mLock.wait(remainingTimeMillis);
+                } catch (InterruptedException ie) {
+                    /* ignore */
+                }
+            }
+        }
+    }
+
+    /**
+     * Finds an {@link AccessibilityNodeInfo} by accessibility id in the active
+     * window. The search is performed from the root node.
+     *
+     * @param accessibilityNodeId A unique view id or virtual descendant id for
+     *     which to search.
+     * @return The current window scale, where zero means a failure.
+     */
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityIdInActiveWindow(
+            long accessibilityNodeId) {
+        return findAccessibilityNodeInfoByAccessibilityId(ACTIVE_WINDOW_ID, accessibilityNodeId);
+    }
+
+    /**
+     * Finds an {@link AccessibilityNodeInfo} by accessibility id.
+     *
+     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id for
+     *     which to search.
+     * @return The current window scale, where zero means a failure.
+     */
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
+            int accessibilityWindowId, long accessibilityNodeId) {
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        ensureValidConnection(connectionId);
+        return AccessibilityInteractionClient.getInstance()
+                .findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+                        accessibilityWindowId, accessibilityNodeId);
+    }
+
+    /**
+     * Finds an {@link AccessibilityNodeInfo} by View id in the active
+     * window. The search is performed from the root node.
+     *
+     * @return The current window scale, where zero means a failure.
+     */
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId) {
+        return findAccessibilityNodeInfoByViewId(ACTIVE_WINDOW_ID, ROOT_NODE_ID, viewId);
+    }
+
+    /**
+     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+     * the window whose id is specified and starts from the node whose accessibility
+     * id is specified.
+     *
+     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
+     * @return The current window scale, where zero means a failure.
+     */
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
+            long accessibilityNodeId, int viewId) {
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        ensureValidConnection(connectionId);
+        return AccessibilityInteractionClient.getInstance()
+                .findAccessibilityNodeInfoByViewId(connectionId, accessibilityWindowId,
+                        accessibilityNodeId, viewId);
+    }
+
+    /**
+     * Finds {@link AccessibilityNodeInfo}s by View text in the active
+     * window. The search is performed from the root node.
+     *
+     * @param text The searched text.
+     * @return The current window scale, where zero means a failure.
+     */
+    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByTextInActiveWindow(String text) {
+        return findAccessibilityNodeInfosByText(ACTIVE_WINDOW_ID, ROOT_NODE_ID, text);
+    }
+
+    /**
+     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
+     * insensitive containment. The search is performed in the window whose
+     * id is specified and starts from the node whose accessibility id is
+     * specified.
+     *
+     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
+     * @param text The searched text.
+     * @return The current window scale, where zero means a failure.
+     */
+    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int accessibilityWindowId,
+            long accessibilityNodeId, String text) {
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        ensureValidConnection(connectionId);
+        return AccessibilityInteractionClient.getInstance()
+                .findAccessibilityNodeInfosByText(connectionId, accessibilityWindowId,
+                        accessibilityNodeId, text);
+    }
+
+    /**
+     * Performs an accessibility action on an {@link AccessibilityNodeInfo}
+     * in the active window.
+     *
+     * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
+     * @param action The action to perform.
+     * @return Whether the action was performed.
+     */
+    public boolean performAccessibilityActionInActiveWindow(long accessibilityNodeId, int action) {
+        return performAccessibilityAction(ACTIVE_WINDOW_ID, accessibilityNodeId, action);
+    }
+
+    /**
+     * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
+     *
+     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
+     * @param action The action to perform.
+     * @return Whether the action was performed.
+     */
+    public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
+            int action) {
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        ensureValidConnection(connectionId);
+        return AccessibilityInteractionClient.getInstance().performAccessibilityAction(connectionId,
+                accessibilityWindowId, accessibilityNodeId, action);
+    }
+
+    /**
+     * Gets the root {@link AccessibilityNodeInfo} in the active window.
+     *
+     * @return The root info.
+     */
+    public AccessibilityNodeInfo getRootAccessibilityNodeInfoInActiveWindow() {
+        synchronized (mLock) {
+            if (mLastWindowStateChangeEvent != null) {
+                return mLastWindowStateChangeEvent.getSource();
+            }
+        }
+        return null;
+    }
+
+    private void ensureValidConnection(int connectionId) {
+        if (connectionId == AccessibilityInteractionClient.NO_ID) {
+            throw new IllegalStateException("UiAutomationService not connected."
+                    + " Did you call #register()?");
+        }
+    }
+}
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 894f428..634e4d8 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -960,17 +960,17 @@
         if (anim instanceof ObjectAnimator) {
             ((ObjectAnimator) anim).setCurrentPlayTime(0);
         }
-        if (mListeners != null) {
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator anim) {
-                    currentAppearingAnimations.remove(child);
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator anim) {
+                currentAppearingAnimations.remove(child);
+                if (mListeners != null) {
                     for (TransitionListener listener : mListeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
                     }
                 }
-            });
-        }
+            }
+        });
         currentAppearingAnimations.put(child, anim);
         anim.start();
     }
@@ -998,17 +998,19 @@
         anim.setStartDelay(mDisappearingDelay);
         anim.setDuration(mDisappearingDuration);
         anim.setTarget(child);
-        if (mListeners != null) {
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator anim) {
-                    currentDisappearingAnimations.remove(child);
+        final float preAnimAlpha = child.getAlpha();
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator anim) {
+                currentDisappearingAnimations.remove(child);
+                child.setAlpha(preAnimAlpha);
+                if (mListeners != null) {
                     for (TransitionListener listener : mListeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
                     }
                 }
-            });
-        }
+            }
+        });
         if (anim instanceof ObjectAnimator) {
             ((ObjectAnimator) anim).setCurrentPlayTime(0);
         }
@@ -1024,18 +1026,25 @@
      *
      * @param parent The ViewGroup to which the View is being added.
      * @param child The View being added to the ViewGroup.
+     * @param changesLayout Whether the removal will cause changes in the layout of other views
+     * in the container. INVISIBLE views becoming VISIBLE will not cause changes and thus will not
+     * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
-    public void addChild(ViewGroup parent, View child) {
+    private void addChild(ViewGroup parent, View child, boolean changesLayout) {
         // Want disappearing animations to finish up before proceeding
         cancel(DISAPPEARING);
-        // Also, cancel changing animations so that we start fresh ones from current locations
-        cancel(CHANGE_APPEARING);
+        if (changesLayout) {
+            // Also, cancel changing animations so that we start fresh ones from current locations
+            cancel(CHANGE_APPEARING);
+        }
         if (mListeners != null) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, APPEARING);
             }
         }
-        runChangeTransition(parent, child, APPEARING);
+        if (changesLayout) {
+            runChangeTransition(parent, child, APPEARING);
+        }
         runAppearingTransition(parent, child);
     }
 
@@ -1048,8 +1057,31 @@
      * @param parent The ViewGroup to which the View is being added.
      * @param child The View being added to the ViewGroup.
      */
+    public void addChild(ViewGroup parent, View child) {
+        addChild(parent, child, true);
+    }
+
+    /**
+     * @deprecated Use {@link #showChild(android.view.ViewGroup, android.view.View, int)}.
+     */
+    @Deprecated
     public void showChild(ViewGroup parent, View child) {
-        addChild(parent, child);
+        addChild(parent, child, true);
+    }
+
+    /**
+     * This method is called by ViewGroup when a child view is about to be made visible in the
+     * container. This callback starts the process of a transition; we grab the starting
+     * values, listen for changes to all of the children of the container, and start appropriate
+     * animations.
+     *
+     * @param parent The ViewGroup in which the View is being made visible.
+     * @param child The View being made visible.
+     * @param oldVisibility The previous visibility value of the child View, either
+     * {@link View#GONE} or {@link View#INVISIBLE}.
+     */
+    public void showChild(ViewGroup parent, View child, int oldVisibility) {
+        addChild(parent, child, oldVisibility == View.GONE);
     }
 
     /**
@@ -1060,18 +1092,25 @@
      *
      * @param parent The ViewGroup from which the View is being removed.
      * @param child The View being removed from the ViewGroup.
+     * @param changesLayout Whether the removal will cause changes in the layout of other views
+     * in the container. Views becoming INVISIBLE will not cause changes and thus will not
+     * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
-    public void removeChild(ViewGroup parent, View child) {
+    private void removeChild(ViewGroup parent, View child, boolean changesLayout) {
         // Want appearing animations to finish up before proceeding
         cancel(APPEARING);
-        // Also, cancel changing animations so that we start fresh ones from current locations
-        cancel(CHANGE_DISAPPEARING);
+        if (changesLayout) {
+            // Also, cancel changing animations so that we start fresh ones from current locations
+            cancel(CHANGE_DISAPPEARING);
+        }
         if (mListeners != null) {
             for (TransitionListener listener : mListeners) {
                 listener.startTransition(this, parent, child, DISAPPEARING);
             }
         }
-        runChangeTransition(parent, child, DISAPPEARING);
+        if (changesLayout) {
+            runChangeTransition(parent, child, DISAPPEARING);
+        }
         runDisappearingTransition(parent, child);
     }
 
@@ -1084,8 +1123,31 @@
      * @param parent The ViewGroup from which the View is being removed.
      * @param child The View being removed from the ViewGroup.
      */
+    public void removeChild(ViewGroup parent, View child) {
+        removeChild(parent, child, true);
+    }
+
+    /**
+     * @deprecated Use {@link #hideChild(android.view.ViewGroup, android.view.View, int)}.
+     */
+    @Deprecated
     public void hideChild(ViewGroup parent, View child) {
-        removeChild(parent, child);
+        removeChild(parent, child, true);
+    }
+
+    /**
+     * This method is called by ViewGroup when a child view is about to be hidden in
+     * container. This callback starts the process of a transition; we grab the starting
+     * values, listen for changes to all of the children of the container, and start appropriate
+     * animations.
+     *
+     * @param parent The parent ViewGroup of the View being hidden.
+     * @param child The View being hidden.
+     * @param newVisibility The new visibility value of the child View, either
+     * {@link View#GONE} or {@link View#INVISIBLE}.
+     */
+    public void hideChild(ViewGroup parent, View child, int newVisibility) {
+        removeChild(parent, child, newVisibility == View.GONE);
     }
 
     /**
diff --git a/core/java/android/animation/TimeAnimator.java b/core/java/android/animation/TimeAnimator.java
index 0a96d59..a79f2a3 100644
--- a/core/java/android/animation/TimeAnimator.java
+++ b/core/java/android/animation/TimeAnimator.java
@@ -1,13 +1,11 @@
 package android.animation;
 
 /**
- * This class provides a simple callback mechanism to listeners that is synchronized with other
- * animators in the system. There is no duration, interpolation, or object value-setting
- * with this Animator. Instead, it is simply started and proceeds to send out events on every
- * animation frame to its TimeListener (if set), with information about this animator,
- * the total elapsed time, and the time since the last animation frame.
- *
- * @hide
+ * This class provides a simple callback mechanism to listeners that is synchronized with all
+ * other animators in the system. There is no duration, interpolation, or object value-setting
+ * with this Animator. Instead, it is simply started, after which it proceeds to send out events
+ * on every animation frame to its TimeListener (if set), with information about this animator,
+ * the total elapsed time, and the elapsed time since the previous animation frame.
  */
 public class TimeAnimator extends ValueAnimator {
 
@@ -59,10 +57,10 @@
      * Implementors of this interface can set themselves as update listeners
      * to a <code>TimeAnimator</code> instance to receive callbacks on every animation
      * frame to receive the total time since the animator started and the delta time
-     * since the last frame. The first time the listener is called, totalTime and
-     * deltaTime should both be zero.
-     *
-     * @hide
+     * since the last frame. The first time the listener is called,
+     * deltaTime will be zero. The same is true for totalTime, unless the animator was
+     * set to a specific {@link ValueAnimator#setCurrentPlayTime(long) currentPlayTime}
+     * prior to starting.
      */
     public static interface TimeListener {
         /**
@@ -70,7 +68,8 @@
          * along with information about the elapsed time.</p>
          *
          * @param animation The animator sending out the notification.
-         * @param totalTime The
+         * @param totalTime The total time elapsed since the animator started, in milliseconds.
+         * @param deltaTime The time elapsed since the previous frame, in milliseconds.
          */
         void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime);
 
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index c7a129e..cc1efb9 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -19,6 +19,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.util.AndroidRuntimeException;
 import android.view.Choreographer;
 import android.view.animation.AccelerateDecelerateInterpolator;
@@ -52,6 +53,7 @@
     /**
      * Internal constants
      */
+    private static float sDurationScale = 1.0f;
 
     /**
      * Messages sent to timing handler: START is sent when an animation first begins.
@@ -158,10 +160,12 @@
     //
 
     // How long the animation should last in ms
-    private long mDuration = 300;
+    private long mDuration = (long)(300 * sDurationScale);
+    private long mUnscaledDuration = 300;
 
     // The amount of time in ms to delay starting the animation after start() is called
     private long mStartDelay = 0;
+    private long mUnscaledStartDelay = 0;
 
     // The number of times the animation will repeat. The default is 0, which means the animation
     // will play only once
@@ -217,6 +221,14 @@
      */
     public static final int INFINITE = -1;
 
+
+    /**
+     * @hide
+     */
+    public static void setDurationScale(float durationScale) {
+        sDurationScale = durationScale;
+    }
+
     /**
      * Creates a new ValueAnimator object. This default constructor is primarily for
      * use internally; the factory methods which take parameters are more generally
@@ -453,7 +465,8 @@
             throw new IllegalArgumentException("Animators cannot have negative duration: " +
                     duration);
         }
-        mDuration = duration;
+        mUnscaledDuration = duration;
+        mDuration = (long)(duration * sDurationScale);
         return this;
     }
 
@@ -463,7 +476,7 @@
      * @return The length of the animation, in milliseconds.
      */
     public long getDuration() {
-        return mDuration;
+        return mUnscaledDuration;
     }
 
     /**
@@ -658,7 +671,7 @@
      * @return the number of milliseconds to delay running the animation
      */
     public long getStartDelay() {
-        return mStartDelay;
+        return mUnscaledStartDelay;
     }
 
     /**
@@ -668,7 +681,8 @@
      * @param startDelay The amount of the delay, in milliseconds
      */
     public void setStartDelay(long startDelay) {
-        this.mStartDelay = startDelay;
+        this.mStartDelay = (long)(startDelay * sDurationScale);
+        mUnscaledStartDelay = startDelay;
     }
 
     /**
diff --git a/core/java/android/annotation/SuppressLint.java b/core/java/android/annotation/SuppressLint.java
new file mode 100644
index 0000000..2d3456b
--- /dev/null
+++ b/core/java/android/annotation/SuppressLint.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should ignore the specified warnings for the annotated element. */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+    /**
+     * The set of warnings (identified by the lint issue id) that should be
+     * ignored by lint. It is not an error to specify an unrecognized name.
+     */
+    String[] value();
+}
diff --git a/core/java/android/annotation/TargetApi.java b/core/java/android/annotation/TargetApi.java
new file mode 100644
index 0000000..ea17890
--- /dev/null
+++ b/core/java/android/annotation/TargetApi.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should treat this type as targeting a given API level, no matter what the
+    project target is. */
+@Target({TYPE, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface TargetApi {
+    /**
+     * This sets the target api level for the type..
+     */
+    int value();
+}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4fe9cef..d98d87b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Point;
+import android.os.Binder;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.Parcel;
@@ -975,7 +976,7 @@
     public boolean clearApplicationUserData(String packageName, IPackageDataObserver observer) {
         try {
             return ActivityManagerNative.getDefault().clearApplicationUserData(packageName, 
-                    observer);
+                    observer, Binder.getOrigCallingUser());
         } catch (RemoteException e) {
             return false;
         }
@@ -1442,9 +1443,10 @@
     public int getLauncherLargeIconDensity() {
         final Resources res = mContext.getResources();
         final int density = res.getDisplayMetrics().densityDpi;
+        final int sw = res.getConfiguration().smallestScreenWidthDp;
 
-        if ((res.getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
-                != Configuration.SCREENLAYOUT_SIZE_XLARGE) {
+        if (sw < 600) {
+            // Smaller than approx 7" tablets, use the regular icon size.
             return density;
         }
 
@@ -1456,9 +1458,13 @@
             case DisplayMetrics.DENSITY_HIGH:
                 return DisplayMetrics.DENSITY_XHIGH;
             case DisplayMetrics.DENSITY_XHIGH:
-                return DisplayMetrics.DENSITY_MEDIUM * 2;
+                return DisplayMetrics.DENSITY_XXHIGH;
+            case DisplayMetrics.DENSITY_XXHIGH:
+                return DisplayMetrics.DENSITY_XHIGH * 2;
             default:
-                return density;
+                // The density is some abnormal value.  Return some other
+                // abnormal value that is a reasonable scaling of it.
+                return (int)(density*1.5f);
         }
     }
 
@@ -1471,9 +1477,10 @@
     public int getLauncherLargeIconSize() {
         final Resources res = mContext.getResources();
         final int size = res.getDimensionPixelSize(android.R.dimen.app_icon_size);
+        final int sw = res.getConfiguration().smallestScreenWidthDp;
 
-        if ((res.getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
-                != Configuration.SCREENLAYOUT_SIZE_XLARGE) {
+        if (sw < 600) {
+            // Smaller than approx 7" tablets, use the regular icon size.
             return size;
         }
 
@@ -1487,9 +1494,13 @@
             case DisplayMetrics.DENSITY_HIGH:
                 return (size * DisplayMetrics.DENSITY_XHIGH) / DisplayMetrics.DENSITY_HIGH;
             case DisplayMetrics.DENSITY_XHIGH:
-                return (size * DisplayMetrics.DENSITY_MEDIUM * 2) / DisplayMetrics.DENSITY_XHIGH;
+                return (size * DisplayMetrics.DENSITY_XXHIGH) / DisplayMetrics.DENSITY_XHIGH;
+            case DisplayMetrics.DENSITY_XXHIGH:
+                return (size * DisplayMetrics.DENSITY_XHIGH*2) / DisplayMetrics.DENSITY_XXHIGH;
             default:
-                return size;
+                // The density is some abnormal value.  Return some other
+                // abnormal value that is a reasonable scaling of it.
+                return (int)(size*1.5f);
         }
     }
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7994d7c..5a36466 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -91,7 +91,7 @@
         try {
             getDefault().broadcastIntent(
                 null, intent, null, null, Activity.RESULT_OK, null, null,
-                null /*permission*/, false, true);
+                null /*permission*/, false, true, Binder.getOrigCallingUser());
         } catch (RemoteException ex) {
         }
     }
@@ -306,9 +306,10 @@
             String perm = data.readString();
             boolean serialized = data.readInt() != 0;
             boolean sticky = data.readInt() != 0;
+            int userId = data.readInt();
             int res = broadcastIntent(app, intent, resolvedType, resultTo,
                     resultCode, resultData, resultExtras, perm,
-                    serialized, sticky);
+                    serialized, sticky, userId);
             reply.writeNoException();
             reply.writeInt(res);
             return true;
@@ -320,7 +321,8 @@
             IBinder b = data.readStrongBinder();
             IApplicationThread app = b != null ? ApplicationThreadNative.asInterface(b) : null;
             Intent intent = Intent.CREATOR.createFromParcel(data);
-            unbroadcastIntent(app, intent);
+            int userId = data.readInt();
+            unbroadcastIntent(app, intent, userId);
             reply.writeNoException();
             return true;
         }
@@ -552,15 +554,6 @@
             return true;
         }
 
-        case FINISH_OTHER_INSTANCES_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            ComponentName className = ComponentName.readFromParcel(data);
-            finishOtherInstances(token, className);
-            reply.writeNoException();
-            return true;
-        }
-
         case REPORT_THUMBNAIL_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -677,8 +670,9 @@
             String resolvedType = data.readString();
             b = data.readStrongBinder();
             int fl = data.readInt();
+            int userId = data.readInt();
             IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
-            int res = bindService(app, token, service, resolvedType, conn, fl);
+            int res = bindService(app, token, service, resolvedType, conn, fl, userId);
             reply.writeNoException();
             reply.writeInt(res);
             return true;
@@ -900,7 +894,8 @@
             String packageName = data.readString();
             IPackageDataObserver observer = IPackageDataObserver.Stub.asInterface(
                     data.readStrongBinder());
-            boolean res = clearApplicationUserData(packageName, observer);
+            int userId = data.readInt();
+            boolean res = clearApplicationUserData(packageName, observer, userId);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -1189,22 +1184,6 @@
             return true;
         }
         
-        case REGISTER_ACTIVITY_WATCHER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IActivityWatcher watcher = IActivityWatcher.Stub.asInterface(
-                    data.readStrongBinder());
-            registerActivityWatcher(watcher);
-            return true;
-        }
-        
-        case UNREGISTER_ACTIVITY_WATCHER_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IActivityWatcher watcher = IActivityWatcher.Stub.asInterface(
-                    data.readStrongBinder());
-            unregisterActivityWatcher(watcher);
-            return true;
-        }
-        
         case START_ACTIVITY_IN_PACKAGE_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -1819,7 +1798,7 @@
             Intent intent, String resolvedType,  IIntentReceiver resultTo,
             int resultCode, String resultData, Bundle map,
             String requiredPermission, boolean serialized,
-            boolean sticky) throws RemoteException
+            boolean sticky, int userId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -1834,6 +1813,7 @@
         data.writeString(requiredPermission);
         data.writeInt(serialized ? 1 : 0);
         data.writeInt(sticky ? 1 : 0);
+        data.writeInt(userId);
         mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
@@ -1841,13 +1821,15 @@
         data.recycle();
         return res;
     }
-    public void unbroadcastIntent(IApplicationThread caller, Intent intent) throws RemoteException
+    public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId)
+            throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(caller != null ? caller.asBinder() : null);
         intent.writeToParcel(data, 0);
+        data.writeInt(userId);
         mRemote.transact(UNBROADCAST_INTENT_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -2158,18 +2140,6 @@
         reply.recycle();
         return res;
     }
-    public void finishOtherInstances(IBinder token, ComponentName className) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        ComponentName.writeToParcel(className, data);
-        mRemote.transact(FINISH_OTHER_INSTANCES_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
     public void reportThumbnail(IBinder token,
                                 Bitmap thumbnail, CharSequence description) throws RemoteException
     {
@@ -2319,7 +2289,7 @@
     }
     public int bindService(IApplicationThread caller, IBinder token,
             Intent service, String resolvedType, IServiceConnection connection,
-            int flags) throws RemoteException {
+            int flags, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -2329,6 +2299,7 @@
         data.writeString(resolvedType);
         data.writeStrongBinder(connection.asBinder());
         data.writeInt(flags);
+        data.writeInt(userId);
         mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
@@ -2651,12 +2622,13 @@
         return res;
     }
     public boolean clearApplicationUserData(final String packageName,
-            final IPackageDataObserver observer) throws RemoteException {        
+            final IPackageDataObserver observer, final int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(packageName);
         data.writeStrongBinder(observer.asBinder());
+        data.writeInt(userId);
         mRemote.transact(CLEAR_APP_DATA_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean res = reply.readInt() != 0;
@@ -3017,30 +2989,6 @@
         data.recycle();
     }
     
-    public void registerActivityWatcher(IActivityWatcher watcher)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
-        mRemote.transact(REGISTER_ACTIVITY_WATCHER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    
-    public void unregisterActivityWatcher(IActivityWatcher watcher)
-            throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
-        mRemote.transact(UNREGISTER_ACTIVITY_WATCHER_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    
     public int startActivityInPackage(int uid,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded)
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 455d2f0..bf632a9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -47,6 +47,7 @@
 import android.net.ProxyProperties;
 import android.opengl.GLUtils;
 import android.os.AsyncTask;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
@@ -60,6 +61,7 @@
 import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.os.SystemClock;
+import android.os.UserId;
 import android.util.AndroidRuntimeException;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -132,6 +134,7 @@
     private static final boolean DEBUG_RESULTS = false;
     private static final boolean DEBUG_BACKUP = true;
     private static final boolean DEBUG_CONFIGURATION = false;
+    private static final boolean DEBUG_SERVICE = false;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
     private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";");
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
@@ -635,6 +638,9 @@
             s.intent = intent;
             s.rebind = rebind;
 
+            if (DEBUG_SERVICE)
+                Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
+                        + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
             queueOrSendMessage(H.BIND_SERVICE, s);
         }
 
@@ -1592,7 +1598,8 @@
         boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
         boolean securityViolation = includeCode && ai.uid != 0
                 && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
-                        ? ai.uid != mBoundApplication.appInfo.uid : true);
+                        ? !UserId.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
+                        : true);
         if ((flags&(Context.CONTEXT_INCLUDE_CODE
                 |Context.CONTEXT_IGNORE_SECURITY))
                 == Context.CONTEXT_INCLUDE_CODE) {
@@ -2294,6 +2301,8 @@
 
     private void handleBindService(BindServiceData data) {
         Service s = mServices.get(data.token);
+        if (DEBUG_SERVICE)
+            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
         if (s != null) {
             try {
                 data.intent.setExtrasClassLoader(s.getClassLoader());
@@ -3741,7 +3750,6 @@
     }
 
     final void handleTrimMemory(int level) {
-        WindowManagerImpl.getDefault().trimMemory(level);
         ArrayList<ComponentCallbacks2> callbacks;
 
         synchronized (mPackages) {
@@ -3752,16 +3760,21 @@
         for (int i=0; i<N; i++) {
             callbacks.get(i).onTrimMemory(level);
         }
+        WindowManagerImpl.getDefault().trimMemory(level);
     }
 
     private void setupGraphicsSupport(LoadedApk info) {
+        if (Process.isIsolated()) {
+            // Isolated processes aren't going to do UI.
+            return;
+        }
         try {
             int uid = Process.myUid();
             String[] packages = getPackageManager().getPackagesForUid(uid);
 
             // If there are several packages in this application we won't
             // initialize the graphics disk caches 
-            if (packages.length == 1) {
+            if (packages != null && packages.length == 1) {
                 ContextImpl appContext = new ContextImpl();
                 appContext.init(info, null, this);
 
@@ -3804,7 +3817,7 @@
         // implementation to use the pool executor.  Normally, we use the
         // serialized executor as the default. This has to happen in the
         // main thread so the main looper is set right.
-        if (data.appInfo.targetSdkVersion <= 12) {
+        if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
             AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
         }
 
@@ -4413,7 +4426,7 @@
         });
     }
 
-    public static final ActivityThread systemMain() {
+    public static ActivityThread systemMain() {
         HardwareRenderer.disable(true);
         ActivityThread thread = new ActivityThread();
         thread.attach(true);
@@ -4454,6 +4467,8 @@
         ActivityThread thread = new ActivityThread();
         thread.attach(false);
 
+        AsyncTask.init();
+
         if (false) {
             Looper.myLooper().setMessageLogging(new
                     LogPrinter(Log.DEBUG, "ActivityThread"));
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 180a442..fee2beb 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1177,13 +1177,14 @@
      */
     @Override
     public List<UserInfo> getUsers() {
-        // TODO:
-        // Dummy code, always returns just the primary user
-        ArrayList<UserInfo> users = new ArrayList<UserInfo>();
-        UserInfo primary = new UserInfo(0, "Root!",
-                UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
-        users.add(primary);
-        return users;
+        try {
+            return mPM.getUsers();
+        } catch (RemoteException re) {
+            ArrayList<UserInfo> users = new ArrayList<UserInfo>();
+            UserInfo primary = new UserInfo(0, "Root!", UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
+            users.add(primary);
+            return users;
+        }
     }
 
     /**
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2bf1fb7..ebf692a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -42,7 +42,9 @@
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
+import android.hardware.ISerialManager;
 import android.hardware.SensorManager;
+import android.hardware.SerialManager;
 import android.hardware.usb.IUsbManager;
 import android.hardware.usb.UsbManager;
 import android.location.CountryDetector;
@@ -75,6 +77,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserId;
 import android.os.Vibrator;
 import android.os.storage.StorageManager;
 import android.telephony.TelephonyManager;
@@ -427,6 +430,12 @@
                     return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
                 }});
 
+        registerService(SERIAL_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                    IBinder b = ServiceManager.getService(SERIAL_SERVICE);
+                    return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
+                }});
+
         registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     return new Vibrator();
@@ -896,7 +905,8 @@
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, null, false, false);
+                Activity.RESULT_OK, null, null, null, false, false,
+                Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -908,7 +918,8 @@
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, receiverPermission, false, false);
+                Activity.RESULT_OK, null, null, receiverPermission, false, false,
+                Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -921,7 +932,8 @@
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, receiverPermission, true, false);
+                Activity.RESULT_OK, null, null, receiverPermission, true, false,
+                Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -954,7 +966,7 @@
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, receiverPermission,
-                true, false);
+                true, false, Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -966,7 +978,8 @@
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
-                Activity.RESULT_OK, null, null, null, false, true);
+                Activity.RESULT_OK, null, null, null, false, true,
+                Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -999,7 +1012,7 @@
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, null,
-                true, true);
+                true, true, Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -1014,7 +1027,7 @@
         try {
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().unbroadcastIntent(
-                mMainThread.getApplicationThread(), intent);
+                    mMainThread.getApplicationThread(), intent, Binder.getOrigCallingUser());
         } catch (RemoteException e) {
         }
     }
@@ -1112,6 +1125,12 @@
     @Override
     public boolean bindService(Intent service, ServiceConnection conn,
             int flags) {
+        return bindService(service, conn, flags, UserId.getUserId(Process.myUid()));
+    }
+
+    /** @hide */
+    @Override
+    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
         IServiceConnection sd;
         if (mPackageInfo != null) {
             sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
@@ -1130,7 +1149,7 @@
             int res = ActivityManagerNative.getDefault().bindService(
                 mMainThread.getApplicationThread(), getActivityToken(),
                 service, service.resolveTypeIfNeeded(getContentResolver()),
-                sd, flags);
+                sd, flags, userId);
             if (res < 0) {
                 throw new SecurityException(
                         "Not allowed to bind to service " + service);
@@ -1215,8 +1234,7 @@
 
         int pid = Binder.getCallingPid();
         if (pid != Process.myPid()) {
-            return checkPermission(permission, pid,
-                    Binder.getCallingUid());
+            return checkPermission(permission, pid, Binder.getCallingUid());
         }
         return PackageManager.PERMISSION_DENIED;
     }
@@ -1384,7 +1402,8 @@
             Uri uri, int modeFlags, String message) {
         enforceForUri(
                 modeFlags, checkCallingUriPermission(uri, modeFlags),
-                false, Binder.getCallingUid(), uri, message);
+                false,
+                Binder.getCallingUid(), uri, message);
     }
 
     public void enforceCallingOrSelfUriPermission(
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5222d37..7deb615 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -114,8 +114,8 @@
     public int broadcastIntent(IApplicationThread caller, Intent intent,
             String resolvedType, IIntentReceiver resultTo, int resultCode,
             String resultData, Bundle map, String requiredPermission,
-            boolean serialized, boolean sticky) throws RemoteException;
-    public void unbroadcastIntent(IApplicationThread caller, Intent intent) throws RemoteException;
+            boolean serialized, boolean sticky, int userId) throws RemoteException;
+    public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException;
     /* oneway */
     public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException;
     public void attachApplication(IApplicationThread app) throws RemoteException;
@@ -145,7 +145,6 @@
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
     public void moveTaskBackwards(int task) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
-    public void finishOtherInstances(IBinder token, ComponentName className) throws RemoteException;
     /* oneway */
     public void reportThumbnail(IBinder token,
             Bitmap thumbnail, CharSequence description) throws RemoteException;
@@ -167,7 +166,7 @@
             int id, Notification notification, boolean keepNotification) throws RemoteException;
     public int bindService(IApplicationThread caller, IBinder token,
             Intent service, String resolvedType,
-            IServiceConnection connection, int flags) throws RemoteException;
+            IServiceConnection connection, int flags, int userId) throws RemoteException;
     public boolean unbindService(IServiceConnection connection) throws RemoteException;
     public void publishService(IBinder token,
             Intent intent, IBinder service) throws RemoteException;
@@ -209,7 +208,7 @@
             int flags) throws RemoteException;
     public void cancelIntentSender(IIntentSender sender) throws RemoteException;
     public boolean clearApplicationUserData(final String packageName,
-            final IPackageDataObserver observer) throws RemoteException;
+            final IPackageDataObserver observer, int userId) throws RemoteException;
     public String getPackageForIntentSender(IIntentSender sender) throws RemoteException;
     
     public void setProcessLimit(int max) throws RemoteException;
@@ -295,11 +294,6 @@
     public void stopAppSwitches() throws RemoteException;
     public void resumeAppSwitches() throws RemoteException;
     
-    public void registerActivityWatcher(IActivityWatcher watcher)
-            throws RemoteException;
-    public void unregisterActivityWatcher(IActivityWatcher watcher)
-            throws RemoteException;
-
     public int startActivityInPackage(int uid,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded)
@@ -505,7 +499,7 @@
     int BIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35;
     int UNBIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36;
     int PUBLISH_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37;
-    int FINISH_OTHER_INSTANCES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
+
     int GOING_TO_SLEEP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
     int WAKING_UP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
     int SET_DEBUG_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
@@ -559,8 +553,8 @@
     int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89;
     int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90;
     int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
-    int REGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
-    int UNREGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
+
+
     int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
     int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
     int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
diff --git a/core/java/android/app/IActivityWatcher.aidl b/core/java/android/app/IActivityWatcher.aidl
deleted file mode 100644
index 6737545..0000000
--- a/core/java/android/app/IActivityWatcher.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-package android.app;
-
-/**
- * Callback interface to watch the user's traversal through activities.
- * {@hide}
- */
-oneway interface IActivityWatcher {
-    void activityResuming(int activityId);
-    void closingSystemDialogs(String reason);
-}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 0c6baeb..d9bbb4a 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -36,6 +36,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.StrictMode;
+import android.os.UserId;
 import android.util.AndroidRuntimeException;
 import android.util.Slog;
 import android.view.CompatibilityInfoHolder;
@@ -67,6 +68,8 @@
  */
 public final class LoadedApk {
 
+    private static final String TAG = "LoadedApk";
+
     private final ActivityThread mActivityThread;
     private final ApplicationInfo mApplicationInfo;
     final String mPackageName;
@@ -113,8 +116,13 @@
         mApplicationInfo = aInfo;
         mPackageName = aInfo.packageName;
         mAppDir = aInfo.sourceDir;
-        mResDir = aInfo.uid == Process.myUid() ? aInfo.sourceDir
+        final int myUid = Process.myUid();
+        mResDir = aInfo.uid == myUid ? aInfo.sourceDir
                 : aInfo.publicSourceDir;
+        if (!UserId.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
+            aInfo.dataDir = PackageManager.getDataDirForUser(UserId.getUserId(myUid),
+                    mPackageName);
+        }
         mSharedLibraries = aInfo.sharedLibraryFiles;
         mDataDir = aInfo.dataDir;
         mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index d83d2e6..ff71ee7 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.content.Loader;
+import android.content.Loader.OnLoadCanceledListener;
 import android.os.Bundle;
 import android.util.DebugUtils;
 import android.util.Log;
@@ -219,7 +220,8 @@
     
     boolean mCreatingLoader;
 
-    final class LoaderInfo implements Loader.OnLoadCompleteListener<Object> {
+    final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
+            Loader.OnLoadCanceledListener<Object> {
         final int mId;
         final Bundle mArgs;
         LoaderManager.LoaderCallbacks<Object> mCallbacks;
@@ -271,6 +273,7 @@
                 }
                 if (!mListenerRegistered) {
                     mLoader.registerListener(mId, this);
+                    mLoader.registerOnLoadCanceledListener(this);
                     mListenerRegistered = true;
                 }
                 mLoader.startLoading();
@@ -329,11 +332,21 @@
                     // Let the loader know we're done with it
                     mListenerRegistered = false;
                     mLoader.unregisterListener(this);
+                    mLoader.unregisterOnLoadCanceledListener(this);
                     mLoader.stopLoading();
                 }
             }
         }
-        
+
+        void cancel() {
+            if (DEBUG) Log.v(TAG, "  Canceling: " + this);
+            if (mStarted && mLoader != null && mListenerRegistered) {
+                if (!mLoader.cancelLoad()) {
+                    onLoadCanceled(mLoader);
+                }
+            }
+        }
+
         void destroy() {
             if (DEBUG) Log.v(TAG, "  Destroying: " + this);
             mDestroyed = true;
@@ -361,6 +374,7 @@
                 if (mListenerRegistered) {
                     mListenerRegistered = false;
                     mLoader.unregisterListener(this);
+                    mLoader.unregisterOnLoadCanceledListener(this);
                 }
                 mLoader.reset();
             }
@@ -368,8 +382,38 @@
                 mPendingLoader.destroy();
             }
         }
-        
-        @Override public void onLoadComplete(Loader<Object> loader, Object data) {
+
+        @Override
+        public void onLoadCanceled(Loader<Object> loader) {
+            if (DEBUG) Log.v(TAG, "onLoadCanceled: " + this);
+
+            if (mDestroyed) {
+                if (DEBUG) Log.v(TAG, "  Ignoring load canceled -- destroyed");
+                return;
+            }
+
+            if (mLoaders.get(mId) != this) {
+                // This cancellation message is not coming from the current active loader.
+                // We don't care about it.
+                if (DEBUG) Log.v(TAG, "  Ignoring load canceled -- not active");
+                return;
+            }
+
+            LoaderInfo pending = mPendingLoader;
+            if (pending != null) {
+                // There is a new request pending and we were just
+                // waiting for the old one to cancel or complete before starting
+                // it.  So now it is time, switch over to the new loader.
+                if (DEBUG) Log.v(TAG, "  Switching to pending loader: " + pending);
+                mPendingLoader = null;
+                mLoaders.put(mId, null);
+                destroy();
+                installLoader(pending);
+            }
+        }
+
+        @Override
+        public void onLoadComplete(Loader<Object> loader, Object data) {
             if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
             
             if (mDestroyed) {
@@ -632,7 +676,9 @@
                     } else {
                         // Now we have three active loaders... we'll queue
                         // up this request to be processed once one of the other loaders
-                        // finishes.
+                        // finishes or is canceled.
+                        if (DEBUG) Log.v(TAG, "  Current loader is running; attempting to cancel");
+                        info.cancel();
                         if (info.mPendingLoader != null) {
                             if (DEBUG) Log.v(TAG, "  Removing pending loader: " + info.mPendingLoader);
                             info.mPendingLoader.destroy();
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 8fa95b4..d04e9db 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -551,7 +551,6 @@
         try {
             // If the intent was created from a suggestion, it will always have an explicit
             // component here.
-            Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toUri(0));
             getContext().startActivity(intent);
             // If the search switches to a different activity,
             // SearchDialogWrapper#performActivityResuming
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index c1e28b0..c057d66 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -30,6 +30,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -433,7 +434,12 @@
      */
     public WallpaperInfo getWallpaperInfo() {
         try {
-            return sGlobals.mService.getWallpaperInfo();
+            if (sGlobals.mService == null) {
+                Log.w(TAG, "WallpaperService not running");
+                return null;
+            } else {
+                return sGlobals.mService.getWallpaperInfo();
+            }
         } catch (RemoteException e) {
             return null;
         }
@@ -451,6 +457,10 @@
      * wallpaper.
      */
     public void setResource(int resid) throws IOException {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return;
+        }
         try {
             Resources resources = mContext.getResources();
             /* Set the wallpaper to the default values */
@@ -483,6 +493,10 @@
      * wallpaper.
      */
     public void setBitmap(Bitmap bitmap) throws IOException {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return;
+        }
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
             if (fd == null) {
@@ -515,6 +529,10 @@
      * wallpaper.
      */
     public void setStream(InputStream data) throws IOException {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return;
+        }
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
             if (fd == null) {
@@ -558,6 +576,10 @@
      * mandatory.
      */
     public int getDesiredMinimumWidth() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return 0;
+        }
         try {
             return sGlobals.mService.getWidthHint();
         } catch (RemoteException e) {
@@ -581,6 +603,10 @@
      * mandatory.
      */
     public int getDesiredMinimumHeight() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return 0;
+        }
         try {
             return sGlobals.mService.getHeightHint();
         } catch (RemoteException e) {
@@ -599,7 +625,11 @@
      */
     public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
         try {
-            sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
+            if (sGlobals.mService == null) {
+                Log.w(TAG, "WallpaperService not running");
+            } else {
+                sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);
+            }
         } catch (RemoteException e) {
             // Ignore
         }
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 170171e..a74a268 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -38,15 +38,23 @@
     private static final boolean DEBUG = false;
 
     // This path must match what the WallpaperManagerService uses
-    private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper";
+    // TODO: Will need to change if backing up non-primary user's wallpaper
+    public static final String WALLPAPER_IMAGE = "/data/system/users/0/wallpaper";
+    public static final String WALLPAPER_INFO = "/data/system/users/0/wallpaper_info.xml";
+    // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
+    public static final String WALLPAPER_IMAGE_KEY =
+            "/data/data/com.android.settings/files/wallpaper";
+    public static final String WALLPAPER_INFO_KEY = "/data/system/wallpaper_info.xml";
 
     // Stage file - should be adjacent to the WALLPAPER_IMAGE location.  The wallpapers
     // will be saved to this file from the restore stream, then renamed to the proper
     // location if it's deemed suitable.
-    private static final String STAGE_FILE = "/data/data/com.android.settings/files/wallpaper-tmp";
+    // TODO: Will need to change if backing up non-primary user's wallpaper
+    private static final String STAGE_FILE = "/data/system/users/0/wallpaper-tmp";
 
     Context mContext;
     String[] mFiles;
+    String[] mKeys;
     double mDesiredMinWidth;
     double mDesiredMinHeight;
 
@@ -57,11 +65,12 @@
      * @param context
      * @param files
      */
-    public WallpaperBackupHelper(Context context, String... files) {
+    public WallpaperBackupHelper(Context context, String[] files, String[] keys) {
         super(context);
 
         mContext = context;
         mFiles = files;
+        mKeys = keys;
 
         WallpaperManager wpm;
         wpm = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
@@ -89,7 +98,7 @@
      */
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) {
-        performBackup_checked(oldState, data, newState, mFiles, mFiles);
+        performBackup_checked(oldState, data, newState, mFiles, mKeys);
     }
 
     /**
@@ -99,8 +108,8 @@
      */
     public void restoreEntity(BackupDataInputStream data) {
         final String key = data.getKey();
-        if (isKeyInList(key, mFiles)) {
-            if (key.equals(WALLPAPER_IMAGE)) {
+        if (isKeyInList(key, mKeys)) {
+            if (key.equals(WALLPAPER_IMAGE_KEY)) {
                 // restore the file to the stage for inspection
                 File f = new File(STAGE_FILE);
                 if (writeFile(f, data)) {
@@ -135,9 +144,9 @@
                         f.delete();
                     }
                 }
-            } else {
-                // Some other normal file; just decode it to its destination
-                File f = new File(key);
+            } else if (key.equals(WALLPAPER_INFO_KEY)) {
+                // XML file containing wallpaper info
+                File f = new File(WALLPAPER_INFO);
                 writeFile(f, data);
             }
         }
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 0b54396..da51952 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -53,19 +53,33 @@
     static final boolean DEBUG = false;
 
     final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
+        private final CountDownLatch mDone = new CountDownLatch(1);
 
-        D result;
+        // Set to true to indicate that the task has been posted to a handler for
+        // execution at a later time.  Used to throttle updates.
         boolean waiting;
 
-        private CountDownLatch done = new CountDownLatch(1);
-
         /* Runs on a worker thread */
         @Override
         protected D doInBackground(Void... params) {
             if (DEBUG) Slog.v(TAG, this + " >>> doInBackground");
-            result = AsyncTaskLoader.this.onLoadInBackground();
-            if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground");
-            return result;
+            try {
+                D data = AsyncTaskLoader.this.onLoadInBackground();
+                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground");
+                return data;
+            } catch (OperationCanceledException ex) {
+                if (!isCancelled()) {
+                    // onLoadInBackground threw a canceled exception spuriously.
+                    // This is problematic because it means that the LoaderManager did not
+                    // cancel the Loader itself and still expects to receive a result.
+                    // Additionally, the Loader's own state will not have been updated to
+                    // reflect the fact that the task was being canceled.
+                    // So we treat this case as an unhandled exception.
+                    throw ex;
+                }
+                if (DEBUG) Slog.v(TAG, this + "  <<< doInBackground (was canceled)");
+                return null;
+            }
         }
 
         /* Runs on the UI thread */
@@ -75,25 +89,37 @@
             try {
                 AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
             } finally {
-                done.countDown();
+                mDone.countDown();
             }
         }
 
+        /* Runs on the UI thread */
         @Override
-        protected void onCancelled() {
+        protected void onCancelled(D data) {
             if (DEBUG) Slog.v(TAG, this + " onCancelled");
             try {
-                AsyncTaskLoader.this.dispatchOnCancelled(this, result);
+                AsyncTaskLoader.this.dispatchOnCancelled(this, data);
             } finally {
-                done.countDown();
+                mDone.countDown();
             }
         }
 
+        /* Runs on the UI thread, when the waiting task is posted to a handler.
+         * This method is only executed when task execution was deferred (waiting was true). */
         @Override
         public void run() {
             waiting = false;
             AsyncTaskLoader.this.executePendingTask();
         }
+
+        /* Used for testing purposes to wait for the task to complete. */
+        public void waitForLoader() {
+            try {
+                mDone.await();
+            } catch (InterruptedException e) {
+                // Ignore
+            }
+        }
     }
 
     volatile LoadTask mTask;
@@ -109,7 +135,7 @@
 
     /**
      * Set amount to throttle updates by.  This is the minimum time from
-     * when the last {@link #onLoadInBackground()} call has completed until
+     * when the last {@link #loadInBackground()} call has completed until
      * a new load is scheduled.
      *
      * @param delayMS Amount of delay, in milliseconds.
@@ -130,24 +156,9 @@
         executePendingTask();
     }
 
-    /**
-     * Attempt to cancel the current load task. See {@link AsyncTask#cancel(boolean)}
-     * for more info.  Must be called on the main thread of the process.
-     *
-     * <p>Cancelling is not an immediate operation, since the load is performed
-     * in a background thread.  If there is currently a load in progress, this
-     * method requests that the load be cancelled, and notes this is the case;
-     * once the background thread has completed its work its remaining state
-     * will be cleared.  If another load request comes in during this time,
-     * it will be held until the cancelled load is complete.
-     *
-     * @return Returns <tt>false</tt> if the task could not be cancelled,
-     *         typically because it has already completed normally, or
-     *         because {@link #startLoading()} hasn't been called; returns
-     *         <tt>true</tt> otherwise.
-     */
-    public boolean cancelLoad() {
-        if (DEBUG) Slog.v(TAG, "cancelLoad: mTask=" + mTask);
+    @Override
+    protected boolean onCancelLoad() {
+        if (DEBUG) Slog.v(TAG, "onCancelLoad: mTask=" + mTask);
         if (mTask != null) {
             if (mCancellingTask != null) {
                 // There was a pending task already waiting for a previous
@@ -173,6 +184,7 @@
                 if (DEBUG) Slog.v(TAG, "cancelLoad: cancelled=" + cancelled);
                 if (cancelled) {
                     mCancellingTask = mTask;
+                    cancelLoadInBackground();
                 }
                 mTask = null;
                 return cancelled;
@@ -183,7 +195,10 @@
 
     /**
      * Called if the task was canceled before it was completed.  Gives the class a chance
-     * to properly dispose of the result.
+     * to clean up post-cancellation and to properly dispose of the result.
+     *
+     * @param data The value that was returned by {@link #loadInBackground}, or null
+     * if the task threw {@link OperationCanceledException}.
      */
     public void onCanceled(D data) {
     }
@@ -217,6 +232,8 @@
             if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
             mLastLoadCompleteTime = SystemClock.uptimeMillis();
             mCancellingTask = null;
+            if (DEBUG) Slog.v(TAG, "Delivering cancellation");
+            deliverCancellation();
             executePendingTask();
         }
     }
@@ -239,23 +256,76 @@
     }
 
     /**
+     * Called on a worker thread to perform the actual load and to return
+     * the result of the load operation.
+     *
+     * Implementations should not deliver the result directly, but should return them
+     * from this method, which will eventually end up calling {@link #deliverResult} on
+     * the UI thread.  If implementations need to process the results on the UI thread
+     * they may override {@link #deliverResult} and do so there.
+     *
+     * To support cancellation, this method should periodically check the value of
+     * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
+     * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
+     * directly instead of polling {@link #isLoadInBackgroundCanceled}.
+     *
+     * When the load is canceled, this method may either return normally or throw
+     * {@link OperationCanceledException}.  In either case, the {@link Loader} will
+     * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
+     * result object, if any.
+     *
+     * @return The result of the load operation.
+     *
+     * @throws OperationCanceledException if the load is canceled during execution.
+     *
+     * @see #isLoadInBackgroundCanceled
+     * @see #cancelLoadInBackground
+     * @see #onCanceled
      */
     public abstract D loadInBackground();
 
     /**
-     * Called on a worker thread to perform the actual load. Implementations should not deliver the
-     * result directly, but should return them from this method, which will eventually end up
-     * calling {@link #deliverResult} on the UI thread. If implementations need to process
-     * the results on the UI thread they may override {@link #deliverResult} and do so
-     * there.
+     * Calls {@link #loadInBackground()}.
      *
-     * @return Implementations must return the result of their load operation.
+     * This method is reserved for use by the loader framework.
+     * Subclasses should override {@link #loadInBackground} instead of this method.
+     *
+     * @return The result of the load operation.
+     *
+     * @throws OperationCanceledException if the load is canceled during execution.
+     *
+     * @see #loadInBackground
      */
     protected D onLoadInBackground() {
         return loadInBackground();
     }
 
     /**
+     * Called on the main thread to abort a load in progress.
+     *
+     * Override this method to abort the current invocation of {@link #loadInBackground}
+     * that is running in the background on a worker thread.
+     *
+     * This method should do nothing if {@link #loadInBackground} has not started
+     * running or if it has already finished.
+     *
+     * @see #loadInBackground
+     */
+    public void cancelLoadInBackground() {
+    }
+
+    /**
+     * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
+     *
+     * @return True if the current invocation of {@link #loadInBackground} is being canceled.
+     *
+     * @see #loadInBackground
+     */
+    public boolean isLoadInBackgroundCanceled() {
+        return mCancellingTask != null;
+    }
+
+    /**
      * Locks the current thread until the loader completes the current load
      * operation. Returns immediately if there is no load operation running.
      * Should not be called from the UI thread: calling it from the UI
@@ -268,11 +338,7 @@
     public void waitForLoader() {
         LoadTask task = mTask;
         if (task != null) {
-            try {
-                task.done.await();
-            } catch (InterruptedException e) {
-                // Ignore
-            }
+            task.waitForLoader();
         }
     }
 
diff --git a/core/java/android/content/CancellationSignal.java b/core/java/android/content/CancellationSignal.java
new file mode 100644
index 0000000..2dbbe54
--- /dev/null
+++ b/core/java/android/content/CancellationSignal.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.os.RemoteException;
+
+/**
+ * Provides the ability to cancel an operation in progress.
+ */
+public final class CancellationSignal {
+    private boolean mIsCanceled;
+    private OnCancelListener mOnCancelListener;
+    private ICancellationSignal mRemote;
+
+    /**
+     * Creates a cancellation signal, initially not canceled.
+     */
+    public CancellationSignal() {
+    }
+
+    /**
+     * Returns true if the operation has been canceled.
+     *
+     * @return True if the operation has been canceled.
+     */
+    public boolean isCanceled() {
+        synchronized (this) {
+            return mIsCanceled;
+        }
+    }
+
+    /**
+     * Throws {@link OperationCanceledException} if the operation has been canceled.
+     *
+     * @throws OperationCanceledException if the operation has been canceled.
+     */
+    public void throwIfCanceled() {
+        if (isCanceled()) {
+            throw new OperationCanceledException();
+        }
+    }
+
+    /**
+     * Cancels the operation and signals the cancellation listener.
+     * If the operation has not yet started, then it will be canceled as soon as it does.
+     */
+    public void cancel() {
+        synchronized (this) {
+            if (!mIsCanceled) {
+                mIsCanceled = true;
+                if (mOnCancelListener != null) {
+                    mOnCancelListener.onCancel();
+                }
+                if (mRemote != null) {
+                    try {
+                        mRemote.cancel();
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the cancellation listener to be called when canceled.
+     *
+     * This method is intended to be used by the recipient of a cancellation signal
+     * such as a database or a content provider to handle cancellation requests
+     * while performing a long-running operation.  This method is not intended to be
+     * used by applications themselves.
+     *
+     * If {@link CancellationSignal#cancel} has already been called, then the provided
+     * listener is invoked immediately.
+     *
+     * The listener is called while holding the cancellation signal's lock which is
+     * also held while registering or unregistering the listener.  Because of the lock,
+     * it is not possible for the listener to run after it has been unregistered.
+     * This design choice makes it easier for clients of {@link CancellationSignal} to
+     * prevent race conditions related to listener registration and unregistration.
+     *
+     * @param listener The cancellation listener, or null to remove the current listener.
+     */
+    public void setOnCancelListener(OnCancelListener listener) {
+        synchronized (this) {
+            mOnCancelListener = listener;
+            if (mIsCanceled && listener != null) {
+                listener.onCancel();
+            }
+        }
+    }
+
+    /**
+     * Sets the remote transport.
+     *
+     * @param remote The remote transport, or null to remove.
+     *
+     * @hide
+     */
+    public void setRemote(ICancellationSignal remote) {
+        synchronized (this) {
+            mRemote = remote;
+            if (mIsCanceled && remote != null) {
+                try {
+                    remote.cancel();
+                } catch (RemoteException ex) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates a transport that can be returned back to the caller of
+     * a Binder function and subsequently used to dispatch a cancellation signal.
+     *
+     * @return The new cancellation signal transport.
+     *
+     * @hide
+     */
+    public static ICancellationSignal createTransport() {
+        return new Transport();
+    }
+
+    /**
+     * Given a locally created transport, returns its associated cancellation signal.
+     *
+     * @param transport The locally created transport, or null if none.
+     * @return The associated cancellation signal, or null if none.
+     *
+     * @hide
+     */
+    public static CancellationSignal fromTransport(ICancellationSignal transport) {
+        if (transport instanceof Transport) {
+            return ((Transport)transport).mCancellationSignal;
+        }
+        return null;
+    }
+
+    /**
+     * Listens for cancellation.
+     */
+    public interface OnCancelListener {
+        /**
+         * Called when {@link CancellationSignal#cancel} is invoked.
+         */
+        void onCancel();
+    }
+
+    private static final class Transport extends ICancellationSignal.Stub {
+        final CancellationSignal mCancellationSignal = new CancellationSignal();
+
+        @Override
+        public void cancel() throws RemoteException {
+            mCancellationSignal.cancel();
+        }
+    }
+}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 116ca48..12e3ccf 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -29,6 +29,7 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.RemoteException;
 import android.util.Log;
 
 import java.io.File;
@@ -174,28 +175,33 @@
             return getContentProvider().getClass().getName();
         }
 
+        @Override
         public Cursor query(Uri uri, String[] projection,
-                String selection, String[] selectionArgs, String sortOrder) {
+                String selection, String[] selectionArgs, String sortOrder,
+                ICancellationSignal cancellationSignal) {
             enforceReadPermission(uri);
-            return ContentProvider.this.query(uri, projection, selection,
-                    selectionArgs, sortOrder);
+            return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
+                    CancellationSignal.fromTransport(cancellationSignal));
         }
 
+        @Override
         public String getType(Uri uri) {
             return ContentProvider.this.getType(uri);
         }
 
-
+        @Override
         public Uri insert(Uri uri, ContentValues initialValues) {
             enforceWritePermission(uri);
             return ContentProvider.this.insert(uri, initialValues);
         }
 
+        @Override
         public int bulkInsert(Uri uri, ContentValues[] initialValues) {
             enforceWritePermission(uri);
             return ContentProvider.this.bulkInsert(uri, initialValues);
         }
 
+        @Override
         public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
                 throws OperationApplicationException {
             for (ContentProviderOperation operation : operations) {
@@ -210,17 +216,20 @@
             return ContentProvider.this.applyBatch(operations);
         }
 
+        @Override
         public int delete(Uri uri, String selection, String[] selectionArgs) {
             enforceWritePermission(uri);
             return ContentProvider.this.delete(uri, selection, selectionArgs);
         }
 
+        @Override
         public int update(Uri uri, ContentValues values, String selection,
                 String[] selectionArgs) {
             enforceWritePermission(uri);
             return ContentProvider.this.update(uri, values, selection, selectionArgs);
         }
 
+        @Override
         public ParcelFileDescriptor openFile(Uri uri, String mode)
                 throws FileNotFoundException {
             if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
@@ -228,6 +237,7 @@
             return ContentProvider.this.openFile(uri, mode);
         }
 
+        @Override
         public AssetFileDescriptor openAssetFile(Uri uri, String mode)
                 throws FileNotFoundException {
             if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
@@ -235,6 +245,7 @@
             return ContentProvider.this.openAssetFile(uri, mode);
         }
 
+        @Override
         public Bundle call(String method, String arg, Bundle extras) {
             return ContentProvider.this.call(method, arg, extras);
         }
@@ -251,6 +262,11 @@
             return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts);
         }
 
+        @Override
+        public ICancellationSignal createCancellationSignal() throws RemoteException {
+            return CancellationSignal.createTransport();
+        }
+
         private void enforceReadPermission(Uri uri) {
             final int uid = Binder.getCallingUid();
             if (uid == mMyUid) {
@@ -541,6 +557,75 @@
             String selection, String[] selectionArgs, String sortOrder);
 
     /**
+     * Implement this to handle query requests from clients with support for cancellation.
+     * This method can be called from multiple threads, as described in
+     * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
+     * and Threads</a>.
+     * <p>
+     * Example client call:<p>
+     * <pre>// Request a specific record.
+     * Cursor managedCursor = managedQuery(
+                ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
+                projection,    // Which columns to return.
+                null,          // WHERE clause.
+                null,          // WHERE clause value substitution
+                People.NAME + " ASC");   // Sort order.</pre>
+     * Example implementation:<p>
+     * <pre>// SQLiteQueryBuilder is a helper class that creates the
+        // proper SQL syntax for us.
+        SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
+
+        // Set the table we're querying.
+        qBuilder.setTables(DATABASE_TABLE_NAME);
+
+        // If the query ends in a specific record number, we're
+        // being asked for a specific record, so set the
+        // WHERE clause in our query.
+        if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
+            qBuilder.appendWhere("_id=" + uri.getPathLeafId());
+        }
+
+        // Make the query.
+        Cursor c = qBuilder.query(mDb,
+                projection,
+                selection,
+                selectionArgs,
+                groupBy,
+                having,
+                sortOrder);
+        c.setNotificationUri(getContext().getContentResolver(), uri);
+        return c;</pre>
+     * <p>
+     * If you implement this method then you must also implement the version of
+     * {@link #query(Uri, String[], String, String[], String)} that does not take a cancellation
+     * signal to ensure correct operation on older versions of the Android Framework in
+     * which the cancellation signal overload was not available.
+     *
+     * @param uri The URI to query. This will be the full URI sent by the client;
+     *      if the client is requesting a specific record, the URI will end in a record number
+     *      that the implementation should parse and add to a WHERE or HAVING clause, specifying
+     *      that _id value.
+     * @param projection The list of columns to put into the cursor. If
+     *      null all columns are included.
+     * @param selection A selection criteria to apply when filtering rows.
+     *      If null then all rows are included.
+     * @param selectionArgs You may include ?s in selection, which will be replaced by
+     *      the values from selectionArgs, in order that they appear in the selection.
+     *      The values will be bound as Strings.
+     * @param sortOrder How the rows in the cursor should be sorted.
+     *      If null then the provider is free to define the sort order.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+     * when the query is executed.
+     * @return a Cursor or null.
+     */
+    public Cursor query(Uri uri, String[] projection,
+            String selection, String[] selectionArgs, String sortOrder,
+            CancellationSignal cancellationSignal) {
+        return query(uri, projection, selection, selectionArgs, sortOrder);
+    }
+
+    /**
      * Implement this to handle requests for the MIME type of the data at the
      * given URI.  The returned MIME type should start with
      * <code>vnd.android.cursor.item</code> for a single record,
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 0540109..3ac5e07 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -47,7 +47,20 @@
     /** See {@link ContentProvider#query ContentProvider.query} */
     public Cursor query(Uri url, String[] projection, String selection,
             String[] selectionArgs, String sortOrder) throws RemoteException {
-        return mContentProvider.query(url, projection, selection,  selectionArgs, sortOrder);
+        return query(url, projection, selection,  selectionArgs, sortOrder, null);
+    }
+
+    /** See {@link ContentProvider#query ContentProvider.query} */
+    public Cursor query(Uri url, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
+                    throws RemoteException {
+        ICancellationSignal remoteCancellationSignal = null;
+        if (cancellationSignal != null) {
+            remoteCancellationSignal = mContentProvider.createCancellationSignal();
+            cancellationSignal.setRemote(remoteCancellationSignal);
+        }
+        return mContentProvider.query(url, projection, selection,  selectionArgs, sortOrder,
+                remoteCancellationSignal);
     }
 
     /** See {@link ContentProvider#getType ContentProvider.getType} */
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index b089bf2..eb83dbc 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -21,7 +21,6 @@
 import android.database.BulkCursorToCursorAdaptor;
 import android.database.Cursor;
 import android.database.CursorToBulkCursorAdaptor;
-import android.database.CursorWindow;
 import android.database.DatabaseUtils;
 import android.database.IBulkCursor;
 import android.database.IContentObserver;
@@ -41,8 +40,6 @@
  * {@hide}
  */
 abstract public class ContentProviderNative extends Binder implements IContentProvider {
-    private static final String TAG = "ContentProvider";
-
     public ContentProviderNative()
     {
         attachInterface(this, descriptor);
@@ -108,8 +105,11 @@
                     String sortOrder = data.readString();
                     IContentObserver observer = IContentObserver.Stub.asInterface(
                             data.readStrongBinder());
+                    ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
+                            data.readStrongBinder());
 
-                    Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder);
+                    Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder,
+                            cancellationSignal);
                     if (cursor != null) {
                         CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
                                 cursor, observer, getProviderName());
@@ -295,6 +295,16 @@
                     }
                     return true;
                 }
+
+                case CREATE_CANCELATION_SIGNAL_TRANSACTION:
+                {
+                    data.enforceInterface(IContentProvider.descriptor);
+
+                    ICancellationSignal cancellationSignal = createCancellationSignal();
+                    reply.writeNoException();
+                    reply.writeStrongBinder(cancellationSignal.asBinder());
+                    return true;
+                }
             }
         } catch (Exception e) {
             DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -324,7 +334,8 @@
     }
 
     public Cursor query(Uri url, String[] projection, String selection,
-            String[] selectionArgs, String sortOrder) throws RemoteException {
+            String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
+                    throws RemoteException {
         BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -352,6 +363,7 @@
             }
             data.writeString(sortOrder);
             data.writeStrongBinder(adaptor.getObserver().asBinder());
+            data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
 
             mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
 
@@ -620,5 +632,24 @@
         }
     }
 
+    public ICancellationSignal createCancellationSignal() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        try {
+            data.writeInterfaceToken(IContentProvider.descriptor);
+
+            mRemote.transact(IContentProvider.CREATE_CANCELATION_SIGNAL_TRANSACTION,
+                    data, reply, 0);
+
+            DatabaseUtils.readExceptionFromParcel(reply);
+            ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
+                    reply.readStrongBinder());
+            return cancellationSignal;
+        } finally {
+            data.recycle();
+            reply.recycle();
+        }
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0debb84..96a65da 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -22,6 +22,7 @@
 import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
 import android.app.AppGlobals;
+import android.content.ContentProvider.Transport;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
@@ -302,13 +303,62 @@
      */
     public final Cursor query(Uri uri, String[] projection,
             String selection, String[] selectionArgs, String sortOrder) {
+        return query(uri, projection, selection, selectionArgs, sortOrder, null);
+    }
+
+    /**
+     * <p>
+     * Query the given URI, returning a {@link Cursor} over the result set.
+     * </p>
+     * <p>
+     * For best performance, the caller should follow these guidelines:
+     * <ul>
+     * <li>Provide an explicit projection, to prevent
+     * reading data from storage that aren't going to be used.</li>
+     * <li>Use question mark parameter markers such as 'phone=?' instead of
+     * explicit values in the {@code selection} parameter, so that queries
+     * that differ only by those values will be recognized as the same
+     * for caching purposes.</li>
+     * </ul>
+     * </p>
+     *
+     * @param uri The URI, using the content:// scheme, for the content to
+     *         retrieve.
+     * @param projection A list of which columns to return. Passing null will
+     *         return all columns, which is inefficient.
+     * @param selection A filter declaring which rows to return, formatted as an
+     *         SQL WHERE clause (excluding the WHERE itself). Passing null will
+     *         return all rows for the given URI.
+     * @param selectionArgs You may include ?s in selection, which will be
+     *         replaced by the values from selectionArgs, in the order that they
+     *         appear in the selection. The values will be bound as Strings.
+     * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
+     *         clause (excluding the ORDER BY itself). Passing null will use the
+     *         default sort order, which may be unordered.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+     * when the query is executed.
+     * @return A Cursor object, which is positioned before the first entry, or null
+     * @see Cursor
+     */
+    public final Cursor query(final Uri uri, String[] projection,
+            String selection, String[] selectionArgs, String sortOrder,
+            CancellationSignal cancellationSignal) {
         IContentProvider provider = acquireProvider(uri);
         if (provider == null) {
             return null;
         }
         try {
             long startTime = SystemClock.uptimeMillis();
-            Cursor qCursor = provider.query(uri, projection, selection, selectionArgs, sortOrder);
+
+            ICancellationSignal remoteCancellationSignal = null;
+            if (cancellationSignal != null) {
+                cancellationSignal.throwIfCanceled();
+                remoteCancellationSignal = provider.createCancellationSignal();
+                cancellationSignal.setRemote(remoteCancellationSignal);
+            }
+            Cursor qCursor = provider.query(uri, projection,
+                    selection, selectionArgs, sortOrder, remoteCancellationSignal);
             if (qCursor == null) {
                 releaseProvider(provider);
                 return null;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index bfbd0ac..6d4cdae 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1307,6 +1307,15 @@
             int flags);
 
     /**
+     * Same as {@link #bindService(Intent, ServiceConnection, int)}, but with an explicit userId
+     * argument for use by system server and other multi-user aware code.
+     * @hide
+     */
+    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * Disconnect from an application service.  You will no longer receive
      * calls as the service is restarted, and the service is now allowed to
      * stop at any time.
@@ -1789,6 +1798,17 @@
     public static final String USB_SERVICE = "usb";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a {@link
+     * android.hardware.SerialManager} for access to serial ports.
+     *
+     * @see #getSystemService
+     * @see android.harware.SerialManager
+     *
+     * @hide
+     */
+    public static final String SERIAL_SERVICE = "serial";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 3928aaf..cd8d87f 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -370,6 +370,12 @@
         return mBase.bindService(service, conn, flags);
     }
 
+    /** @hide */
+    @Override
+    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+        return mBase.bindService(service, conn, flags, userId);
+    }
+
     @Override
     public void unbindService(ServiceConnection conn) {
         mBase.unbindService(conn);
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 7af535b..aed3728 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -19,7 +19,6 @@
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.AsyncTask;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -49,18 +48,42 @@
     String mSortOrder;
 
     Cursor mCursor;
+    CancellationSignal mCancellationSignal;
 
     /* Runs on a worker thread */
     @Override
     public Cursor loadInBackground() {
-        Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
-                mSelectionArgs, mSortOrder);
-        if (cursor != null) {
-            // Ensure the cursor window is filled
-            cursor.getCount();
-            registerContentObserver(cursor, mObserver);
+        synchronized (this) {
+            if (isLoadInBackgroundCanceled()) {
+                throw new OperationCanceledException();
+            }
+            mCancellationSignal = new CancellationSignal();
         }
-        return cursor;
+        try {
+            Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
+                    mSelectionArgs, mSortOrder, mCancellationSignal);
+            if (cursor != null) {
+                // Ensure the cursor window is filled
+                cursor.getCount();
+                registerContentObserver(cursor, mObserver);
+            }
+            return cursor;
+        } finally {
+            synchronized (this) {
+                mCancellationSignal = null;
+            }
+        }
+    }
+
+    @Override
+    public void cancelLoadInBackground() {
+        super.cancelLoadInBackground();
+
+        synchronized (this) {
+            if (mCancellationSignal != null) {
+                mCancellationSignal.cancel();
+            }
+        }
     }
 
     /**
diff --git a/libs/rs/rsFifo.cpp b/core/java/android/content/ICancellationSignal.aidl
similarity index 69%
copy from libs/rs/rsFifo.cpp
copy to core/java/android/content/ICancellationSignal.aidl
index 3d5d8c4..cf1c5d3 100644
--- a/libs/rs/rsFifo.cpp
+++ b/core/java/android/content/ICancellationSignal.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -14,18 +14,11 @@
  * limitations under the License.
  */
 
-#include "rsFifoSocket.h"
-#include "utils/Timers.h"
-#include "utils/StopWatch.h"
+package android.content;
 
-using namespace android;
-using namespace android::renderscript;
-
-Fifo::Fifo() {
-
+/**
+ * @hide
+ */
+interface ICancellationSignal {
+    oneway void cancel();
 }
-
-Fifo::~Fifo() {
-
-}
-
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 2a67ff8..16478b7 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -34,7 +34,8 @@
  */
 public interface IContentProvider extends IInterface {
     public Cursor query(Uri url, String[] projection, String selection,
-            String[] selectionArgs, String sortOrder) throws RemoteException;
+            String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
+                    throws RemoteException;
     public String getType(Uri url) throws RemoteException;
     public Uri insert(Uri url, ContentValues initialValues)
             throws RemoteException;
@@ -50,6 +51,7 @@
     public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
             throws RemoteException, OperationApplicationException;
     public Bundle call(String method, String arg, Bundle extras) throws RemoteException;
+    public ICancellationSignal createCancellationSignal() throws RemoteException;
 
     // Data interchange.
     public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
@@ -71,4 +73,5 @@
     static final int CALL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 20;
     static final int GET_STREAM_TYPES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 21;
     static final int OPEN_TYPED_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 22;
+    static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23;
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e3b1f54..ab62c44 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -43,6 +43,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Locale;
 import java.util.Set;
 
 /**
@@ -2956,6 +2957,13 @@
      */
     public static final int FLAG_RECEIVER_REPLACE_PENDING = 0x20000000;
     /**
+     * If set, when sending a broadcast the recipient is allowed to run at
+     * foreground priority, with a shorter timeout interval.  During normal
+     * broadcasts the receivers are not automatically hoisted out of the
+     * background priority class.
+     */
+    public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
+    /**
      * If set, when sending a broadcast <i>before boot has completed</i> only
      * registered receivers will be called -- no BroadcastReceiver components
      * will be launched.  Sticky intent state will be recorded properly even
@@ -2968,14 +2976,14 @@
      *
      * @hide
      */
-    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x10000000;
+    public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x08000000;
     /**
      * Set when this broadcast is for a boot upgrade, a special mode that
      * allows the broadcast to be sent before the system is ready and launches
      * the app process with no providers running in it.
      * @hide
      */
-    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x08000000;
+    public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x04000000;
 
     /**
      * @hide Flags that can't be changed with PendingIntent.
@@ -4420,22 +4428,24 @@
 
     /**
      * Set the data this intent is operating on.  This method automatically
-     * clears any type that was previously set by {@link #setType}.
+     * clears any type that was previously set by {@link #setType} or
+     * {@link #setTypeAndNormalize}.
      *
-     * <p><em>Note: scheme and host name matching in the Android framework is
-     * case-sensitive, unlike the formal RFC.  As a result,
-     * you should always ensure that you write your Uri with these elements
-     * using lower case letters, and normalize any Uris you receive from
-     * outside of Android to ensure the scheme and host is lower case.</em></p>
+     * <p><em>Note: scheme matching in the Android framework is
+     * case-sensitive, unlike the formal RFC. As a result,
+     * you should always write your Uri with a lower case scheme,
+     * or use {@link Uri#normalize} or
+     * {@link #setDataAndNormalize}
+     * to ensure that the scheme is converted to lower case.</em>
      *
-     * @param data The URI of the data this intent is now targeting.
+     * @param data The Uri of the data this intent is now targeting.
      *
      * @return Returns the same Intent object, for chaining multiple calls
      * into a single statement.
      *
      * @see #getData
-     * @see #setType
-     * @see #setDataAndType
+     * @see #setDataAndNormalize
+     * @see android.net.Intent#normalize
      */
     public Intent setData(Uri data) {
         mData = data;
@@ -4444,16 +4454,45 @@
     }
 
     /**
-     * Set an explicit MIME data type.  This is used to create intents that
-     * only specify a type and not data, for example to indicate the type of
-     * data to return.  This method automatically clears any data that was
-     * previously set by {@link #setData}.
+     * Normalize and set the data this intent is operating on.
+     *
+     * <p>This method automatically clears any type that was
+     * previously set (for example, by {@link #setType}).
+     *
+     * <p>The data Uri is normalized using
+     * {@link android.net.Uri#normalize} before it is set,
+     * so really this is just a convenience method for
+     * <pre>
+     * setData(data.normalize())
+     * </pre>
+     *
+     * @param data The Uri of the data this intent is now targeting.
+     *
+     * @return Returns the same Intent object, for chaining multiple calls
+     * into a single statement.
+     *
+     * @see #getData
+     * @see #setType
+     * @see android.net.Uri#normalize
+     */
+    public Intent setDataAndNormalize(Uri data) {
+        return setData(data.normalize());
+    }
+
+    /**
+     * Set an explicit MIME data type.
+     *
+     * <p>This is used to create intents that only specify a type and not data,
+     * for example to indicate the type of data to return.
+     *
+     * <p>This method automatically clears any data that was
+     * previously set (for example by {@link #setData}).
      *
      * <p><em>Note: MIME type matching in the Android framework is
      * case-sensitive, unlike formal RFC MIME types.  As a result,
      * you should always write your MIME types with lower case letters,
-     * and any MIME types you receive from outside of Android should be
-     * converted to lower case before supplying them here.</em></p>
+     * or use {@link #normalizeMimeType} or {@link #setTypeAndNormalize}
+     * to ensure that it is converted to lower case.</em>
      *
      * @param type The MIME type of the data being handled by this intent.
      *
@@ -4461,8 +4500,9 @@
      * into a single statement.
      *
      * @see #getType
-     * @see #setData
+     * @see #setTypeAndNormalize
      * @see #setDataAndType
+     * @see #normalizeMimeType
      */
     public Intent setType(String type) {
         mData = null;
@@ -4471,26 +4511,58 @@
     }
 
     /**
-     * (Usually optional) Set the data for the intent along with an explicit
-     * MIME data type.  This method should very rarely be used -- it allows you
-     * to override the MIME type that would ordinarily be inferred from the
-     * data with your own type given here.
+     * Normalize and set an explicit MIME data type.
      *
-     * <p><em>Note: MIME type, Uri scheme, and host name matching in the
-     * Android framework is case-sensitive, unlike the formal RFC definitions.
-     * As a result, you should always write these elements with lower case letters,
-     * and normalize any MIME types or Uris you receive from
-     * outside of Android to ensure these elements are lower case before
-     * supplying them here.</em></p>
+     * <p>This is used to create intents that only specify a type and not data,
+     * for example to indicate the type of data to return.
      *
-     * @param data The URI of the data this intent is now targeting.
+     * <p>This method automatically clears any data that was
+     * previously set (for example by {@link #setData}).
+     *
+     * <p>The MIME type is normalized using
+     * {@link #normalizeMimeType} before it is set,
+     * so really this is just a convenience method for
+     * <pre>
+     * setType(Intent.normalizeMimeType(type))
+     * </pre>
+     *
      * @param type The MIME type of the data being handled by this intent.
      *
      * @return Returns the same Intent object, for chaining multiple calls
      * into a single statement.
      *
+     * @see #getType
      * @see #setData
+     * @see #normalizeMimeType
+     */
+    public Intent setTypeAndNormalize(String type) {
+        return setType(normalizeMimeType(type));
+    }
+
+    /**
+     * (Usually optional) Set the data for the intent along with an explicit
+     * MIME data type.  This method should very rarely be used -- it allows you
+     * to override the MIME type that would ordinarily be inferred from the
+     * data with your own type given here.
+     *
+     * <p><em>Note: MIME type and Uri scheme matching in the
+     * Android framework is case-sensitive, unlike the formal RFC definitions.
+     * As a result, you should always write these elements with lower case letters,
+     * or use {@link #normalizeMimeType} or {@link android.net.Uri#normalize} or
+     * {@link #setDataAndTypeAndNormalize}
+     * to ensure that they are converted to lower case.</em>
+     *
+     * @param data The Uri of the data this intent is now targeting.
+     * @param type The MIME type of the data being handled by this intent.
+     *
+     * @return Returns the same Intent object, for chaining multiple calls
+     * into a single statement.
+     *
      * @see #setType
+     * @see #setData
+     * @see #normalizeMimeType
+     * @see android.net.Uri#normalize
+     * @see #setDataAndTypeAndNormalize
      */
     public Intent setDataAndType(Uri data, String type) {
         mData = data;
@@ -4499,6 +4571,35 @@
     }
 
     /**
+     * (Usually optional) Normalize and set both the data Uri and an explicit
+     * MIME data type.  This method should very rarely be used -- it allows you
+     * to override the MIME type that would ordinarily be inferred from the
+     * data with your own type given here.
+     *
+     * <p>The data Uri and the MIME type are normalize using
+     * {@link android.net.Uri#normalize} and {@link #normalizeMimeType}
+     * before they are set, so really this is just a convenience method for
+     * <pre>
+     * setDataAndType(data.normalize(), Intent.normalizeMimeType(type))
+     * </pre>
+     *
+     * @param data The Uri of the data this intent is now targeting.
+     * @param type The MIME type of the data being handled by this intent.
+     *
+     * @return Returns the same Intent object, for chaining multiple calls
+     * into a single statement.
+     *
+     * @see #setType
+     * @see #setData
+     * @see #setDataAndType
+     * @see #normalizeMimeType
+     * @see android.net.Uri#normalize
+     */
+    public Intent setDataAndTypeAndNormalize(Uri data, String type) {
+        return setDataAndType(data.normalize(), normalizeMimeType(type));
+    }
+
+    /**
      * Add a new category to the intent.  Categories provide additional detail
      * about the action the intent is perform.  When resolving an intent, only
      * activities that provide <em>all</em> of the requested categories will be
@@ -5566,7 +5667,7 @@
      *
      * <ul>
      * <li> action, as set by {@link #setAction}.
-     * <li> data URI and MIME type, as set by {@link #setData(Uri)},
+     * <li> data Uri and MIME type, as set by {@link #setData(Uri)},
      * {@link #setType(String)}, or {@link #setDataAndType(Uri, String)}.
      * <li> categories, as set by {@link #addCategory}.
      * <li> package, as set by {@link #setPackage}.
@@ -6229,4 +6330,38 @@
 
         return intent;
     }
+
+    /**
+     * Normalize a MIME data type.
+     *
+     * <p>A normalized MIME type has white-space trimmed,
+     * content-type parameters removed, and is lower-case.
+     * This aligns the type with Android best practices for
+     * intent filtering.
+     *
+     * <p>For example, "text/plain; charset=utf-8" becomes "text/plain".
+     * "text/x-vCard" becomes "text/x-vcard".
+     *
+     * <p>All MIME types received from outside Android (such as user input,
+     * or external sources like Bluetooth, NFC, or the Internet) should
+     * be normalized before they are used to create an Intent.
+     *
+     * @param type MIME data type to normalize
+     * @return normalized MIME data type, or null if the input was null
+     * @see {@link #setType}
+     * @see {@link #setTypeAndNormalize}
+     */
+    public static String normalizeMimeType(String type) {
+        if (type == null) {
+            return null;
+        }
+
+        type = type.trim().toLowerCase(Locale.US);
+
+        final int semicolonIndex = type.indexOf(';');
+        if (semicolonIndex != -1) {
+            type = type.substring(0, semicolonIndex);
+        }
+        return type;
+    }
 }
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index ac05682..3052414 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -52,6 +52,7 @@
 public class Loader<D> {
     int mId;
     OnLoadCompleteListener<D> mListener;
+    OnLoadCanceledListener<D> mOnLoadCanceledListener;
     Context mContext;
     boolean mStarted = false;
     boolean mAbandoned = false;
@@ -100,6 +101,23 @@
     }
 
     /**
+     * Interface that is implemented to discover when a Loader has been canceled
+     * before it finished loading its data.  You do not normally need to implement
+     * this yourself; it is used in the implementation of {@link android.app.LoaderManager}
+     * to find out when a Loader it is managing has been canceled so that it
+     * can schedule the next Loader.  This interface should only be used if a
+     * Loader is not being used in conjunction with LoaderManager.
+     */
+    public interface OnLoadCanceledListener<D> {
+        /**
+         * Called on the thread that created the Loader when the load is canceled.
+         *
+         * @param loader the loader that canceled the load
+         */
+        public void onLoadCanceled(Loader<D> loader);
+    }
+
+    /**
      * Stores away the application context associated with context.
      * Since Loaders can be used across multiple activities it's dangerous to
      * store the context directly; always use {@link #getContext()} to retrieve
@@ -127,6 +145,18 @@
     }
 
     /**
+     * Informs the registered {@link OnLoadCanceledListener} that the load has been canceled.
+     * Should only be called by subclasses.
+     *
+     * Must be called from the process's main thread.
+     */
+    public void deliverCancellation() {
+        if (mOnLoadCanceledListener != null) {
+            mOnLoadCanceledListener.onLoadCanceled(this);
+        }
+    }
+
+    /**
      * @return an application context retrieved from the Context passed to the constructor.
      */
     public Context getContext() {
@@ -171,6 +201,40 @@
     }
 
     /**
+     * Registers a listener that will receive callbacks when a load is canceled.
+     * The callback will be called on the process's main thread so it's safe to
+     * pass the results to widgets.
+     *
+     * Must be called from the process's main thread.
+     *
+     * @param listener The listener to register.
+     */
+    public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+        if (mOnLoadCanceledListener != null) {
+            throw new IllegalStateException("There is already a listener registered");
+        }
+        mOnLoadCanceledListener = listener;
+    }
+
+    /**
+     * Unregisters a listener that was previously added with
+     * {@link #registerOnLoadCanceledListener}.
+     *
+     * Must be called from the process's main thread.
+     *
+     * @param listener The listener to unregister.
+     */
+    public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+        if (mOnLoadCanceledListener == null) {
+            throw new IllegalStateException("No listener register");
+        }
+        if (mOnLoadCanceledListener != listener) {
+            throw new IllegalArgumentException("Attempting to unregister the wrong listener");
+        }
+        mOnLoadCanceledListener = null;
+    }
+
+    /**
      * Return whether this load has been started.  That is, its {@link #startLoading()}
      * has been called and no calls to {@link #stopLoading()} or
      * {@link #reset()} have yet been made.
@@ -234,6 +298,43 @@
     }
 
     /**
+     * Attempt to cancel the current load task.
+     * Must be called on the main thread of the process.
+     *
+     * <p>Cancellation is not an immediate operation, since the load is performed
+     * in a background thread.  If there is currently a load in progress, this
+     * method requests that the load be canceled, and notes this is the case;
+     * once the background thread has completed its work its remaining state
+     * will be cleared.  If another load request comes in during this time,
+     * it will be held until the canceled load is complete.
+     *
+     * @return Returns <tt>false</tt> if the task could not be canceled,
+     * typically because it has already completed normally, or
+     * because {@link #startLoading()} hasn't been called; returns
+     * <tt>true</tt> otherwise.  When <tt>true</tt> is returned, the task
+     * is still running and the {@link OnLoadCanceledListener} will be called
+     * when the task completes.
+     */
+    public boolean cancelLoad() {
+        return onCancelLoad();
+    }
+
+    /**
+     * Subclasses must implement this to take care of requests to {@link #cancelLoad()}.
+     * This will always be called from the process's main thread.
+     *
+     * @return Returns <tt>false</tt> if the task could not be canceled,
+     * typically because it has already completed normally, or
+     * because {@link #startLoading()} hasn't been called; returns
+     * <tt>true</tt> otherwise.  When <tt>true</tt> is returned, the task
+     * is still running and the {@link OnLoadCanceledListener} will be called
+     * when the task completes.
+     */
+    protected boolean onCancelLoad() {
+        return false;
+    }
+
+    /**
      * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
      * loaded data set and load a new one.  This simply calls through to the
      * implementation's {@link #onForceLoad()}.  You generally should only call this
diff --git a/core/java/android/content/OperationCanceledException.java b/core/java/android/content/OperationCanceledException.java
new file mode 100644
index 0000000..d783a07
--- /dev/null
+++ b/core/java/android/content/OperationCanceledException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+/**
+ * An exception type that is thrown when an operation in progress is canceled.
+ *
+ * @see CancellationSignal
+ */
+public class OperationCanceledException extends RuntimeException {
+    public OperationCanceledException() {
+        this(null);
+    }
+
+    public OperationCanceledException(String message) {
+        super(message != null ? message : "The operation has been canceled.");
+    }
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index decb974..bb35c29 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -364,4 +364,6 @@
     VerifierDeviceIdentity getVerifierDeviceIdentity();
 
     boolean isFirstBoot();
+
+    List<UserInfo> getUsers();
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8541748d..26a9181 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -28,6 +28,7 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Environment;
 import android.util.AndroidException;
 import android.util.DisplayMetrics;
 
@@ -753,13 +754,6 @@
     public static final int VERIFICATION_REJECT = -1;
 
     /**
-     * Range of IDs allocated for a user.
-     *
-     * @hide
-     */
-    public static final int PER_USER_RANGE = 100000;
-
-    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device's
      * audio pipeline is low-latency, more suitable for audio applications sensitive to delays or
      * lag in sound input or output.
@@ -2615,39 +2609,6 @@
     public abstract void updateUserFlags(int id, int flags);
 
     /**
-     * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
-     * user.
-     * @hide
-     */
-    public static boolean isSameUser(int uid1, int uid2) {
-        return getUserId(uid1) == getUserId(uid2);
-    }
-
-    /**
-     * Returns the user id for a given uid.
-     * @hide
-     */
-    public static int getUserId(int uid) {
-        return uid / PER_USER_RANGE;
-    }
-
-    /**
-     * Returns the uid that is composed from the userId and the appId.
-     * @hide
-     */
-    public static int getUid(int userId, int appId) {
-        return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
-    }
-
-    /**
-     * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
-     * @hide
-     */
-    public static int getAppId(int uid) {
-        return uid % PER_USER_RANGE;
-    }
-
-    /**
      * Returns the device identity that verifiers can use to associate their
      * scheme to a particular device. This should not be used by anything other
      * than a package verifier.
@@ -2656,4 +2617,17 @@
      * @hide
      */
     public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
+
+    /**
+     * Returns the data directory for a particular user and package, given the uid of the package.
+     * @param uid uid of the package, including the userId and appId
+     * @param packageName name of the package
+     * @return the user-specific data directory for the package
+     * @hide
+     */
+    public static String getDataDirForUser(int userId, String packageName) {
+        // TODO: This should be shared with Installer's knowledge of user directory
+        return Environment.getDataDirectory().toString() + "/user/" + userId
+                + "/" + packageName;
+    }
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e593d5b..8029bd5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -24,18 +24,17 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.PatternMatcher;
+import android.os.UserId;
 import android.util.AttributeSet;
 import android.util.Base64;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TypedValue;
-import com.android.internal.util.XmlUtils;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.BufferedInputStream;
 import java.io.File;
@@ -59,6 +58,11 @@
 import java.util.jar.JarFile;
 import java.util.jar.Manifest;
 
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 /**
  * Package archive parsing
  *
@@ -209,6 +213,8 @@
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime) {
 
+        final int userId = Binder.getOrigCallingUser();
+
         PackageInfo pi = new PackageInfo();
         pi.packageName = p.packageName;
         pi.versionCode = p.mVersionCode;
@@ -250,7 +256,8 @@
                     final Activity activity = p.activities.get(i);
                     if (activity.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags);
+                        pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags,
+                                userId);
                     }
                 }
             }
@@ -271,7 +278,7 @@
                     final Activity activity = p.receivers.get(i);
                     if (activity.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags);
+                        pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, userId);
                     }
                 }
             }
@@ -292,7 +299,7 @@
                     final Service service = p.services.get(i);
                     if (service.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags);
+                        pi.services[j++] = generateServiceInfo(p.services.get(i), flags, userId);
                     }
                 }
             }
@@ -313,7 +320,7 @@
                     final Provider provider = p.providers.get(i);
                     if (provider.info.enabled
                         || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
-                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags);
+                        pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, userId);
                     }
                 }
             }
@@ -2574,6 +2581,11 @@
                 false)) {
             s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
         }
+        if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestService_isolatedProcess,
+                false)) {
+            s.info.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
+        }
 
         sa.recycle();
 
@@ -3241,8 +3253,12 @@
     }
 
     public static ApplicationInfo generateApplicationInfo(Package p, int flags) {
+        return generateApplicationInfo(p, flags, UserId.getUserId(Binder.getCallingUid()));
+    }
+
+    public static ApplicationInfo generateApplicationInfo(Package p, int flags, int userId) {
         if (p == null) return null;
-        if (!copyNeeded(flags, p, null)) {
+        if (!copyNeeded(flags, p, null) && userId == 0) {
             // CompatibilityMode is global state. It's safe to modify the instance
             // of the package.
             if (!sCompatibilityModeEnabled) {
@@ -3258,6 +3274,10 @@
 
         // Make shallow copy so we can store the metadata/libraries safely
         ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
+        if (userId != 0) {
+            ai.uid = UserId.getUid(userId, ai.uid);
+            ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName);
+        }
         if ((flags & PackageManager.GET_META_DATA) != 0) {
             ai.metaData = p.mAppMetaData;
         }
@@ -3325,16 +3345,15 @@
         }
     }
 
-    public static final ActivityInfo generateActivityInfo(Activity a,
-            int flags) {
+    public static final ActivityInfo generateActivityInfo(Activity a, int flags, int userId) {
         if (a == null) return null;
-        if (!copyNeeded(flags, a.owner, a.metaData)) {
+        if (!copyNeeded(flags, a.owner, a.metaData) && userId == 0) {
             return a.info;
         }
         // Make shallow copies so we can store the metadata safely
         ActivityInfo ai = new ActivityInfo(a.info);
         ai.metaData = a.metaData;
-        ai.applicationInfo = generateApplicationInfo(a.owner, flags);
+        ai.applicationInfo = generateApplicationInfo(a.owner, flags, userId);
         return ai;
     }
 
@@ -3359,15 +3378,16 @@
         }
     }
 
-    public static final ServiceInfo generateServiceInfo(Service s, int flags) {
+    public static final ServiceInfo generateServiceInfo(Service s, int flags, int userId) {
         if (s == null) return null;
-        if (!copyNeeded(flags, s.owner, s.metaData)) {
+        if (!copyNeeded(flags, s.owner, s.metaData)
+                && userId == UserId.getUserId(s.info.applicationInfo.uid)) {
             return s.info;
         }
         // Make shallow copies so we can store the metadata safely
         ServiceInfo si = new ServiceInfo(s.info);
         si.metaData = s.metaData;
-        si.applicationInfo = generateApplicationInfo(s.owner, flags);
+        si.applicationInfo = generateApplicationInfo(s.owner, flags, userId);
         return si;
     }
 
@@ -3400,12 +3420,12 @@
         }
     }
 
-    public static final ProviderInfo generateProviderInfo(Provider p,
-            int flags) {
+    public static final ProviderInfo generateProviderInfo(Provider p, int flags, int userId) {
         if (p == null) return null;
         if (!copyNeeded(flags, p.owner, p.metaData)
                 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
-                        || p.info.uriPermissionPatterns == null)) {
+                        || p.info.uriPermissionPatterns == null)
+                && userId == 0) {
             return p.info;
         }
         // Make shallow copies so we can store the metadata safely
@@ -3414,7 +3434,7 @@
         if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
             pi.uriPermissionPatterns = null;
         }
-        pi.applicationInfo = generateApplicationInfo(p.owner, flags);
+        pi.applicationInfo = generateApplicationInfo(p.owner, flags, userId);
         return pi;
     }
 
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 612e345..7ee84ab 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -42,10 +42,17 @@
     public static final int FLAG_STOP_WITH_TASK = 0x0001;
 
     /**
+     * Bit in {@link #flags}: If set, the service will run in its own
+     * isolated process.  Set from the
+     * {@link android.R.attr#isolatedProcess} attribute.
+     */
+    public static final int FLAG_ISOLATED_PROCESS = 0x0002;
+
+    /**
      * Options that have been set in the service declaration in the
      * manifest.
      * These include:
-     * {@link #FLAG_STOP_WITH_TASK}
+     * {@link #FLAG_STOP_WITH_TASK}, {@link #FLAG_ISOLATED_PROCESS}.
      */
     public int flags;
 
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6015668..e04b2f7 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -347,6 +347,7 @@
             sb.append(" (no locale)");
         }
         switch (textLayoutDirection) {
+            case LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE: /* ltr not interesting */ break;
             case LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
             default: sb.append(" layoutdir="); sb.append(textLayoutDirection); break;
         }
diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java
index a9a71cf..59ec89d 100644
--- a/core/java/android/database/Cursor.java
+++ b/core/java/android/database/Cursor.java
@@ -341,6 +341,7 @@
      * Deactivates the Cursor, making all calls on it fail until {@link #requery} is called.
      * Inactive Cursors use fewer resources than active Cursors.
      * Calling {@link #requery} will make the cursor active again.
+     * @deprecated Since {@link #requery()} is deprecated, so too is this.
      */
     void deactivate();
 
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index b69d9bf..0022118 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -21,6 +21,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.OperationApplicationException;
+import android.content.OperationCanceledException;
 import android.database.sqlite.SQLiteAbortException;
 import android.database.sqlite.SQLiteConstraintException;
 import android.database.sqlite.SQLiteDatabase;
@@ -107,6 +108,9 @@
             code = 9;
         } else if (e instanceof OperationApplicationException) {
             code = 10;
+        } else if (e instanceof OperationCanceledException) {
+            code = 11;
+            logException = false;
         } else {
             reply.writeException(e);
             Log.e(TAG, "Writing exception to parcel", e);
@@ -178,6 +182,8 @@
                 throw new SQLiteDiskIOException(msg);
             case 9:
                 throw new SQLiteException(msg);
+            case 11:
+                throw new OperationCanceledException(msg);
             default:
                 reply.readException(code, msg);
         }
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 72f62fd..b5cef81 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -19,6 +19,8 @@
 import dalvik.system.BlockGuard;
 import dalvik.system.CloseGuard;
 
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
 import android.database.Cursor;
 import android.database.CursorWindow;
 import android.database.DatabaseUtils;
@@ -82,7 +84,7 @@
  *
  * @hide
  */
-public final class SQLiteConnection {
+public final class SQLiteConnection implements CancellationSignal.OnCancelListener {
     private static final String TAG = "SQLiteConnection";
     private static final boolean DEBUG = false;
 
@@ -108,6 +110,12 @@
 
     private boolean mOnlyAllowReadOnlyOperations;
 
+    // The number of times attachCancellationSignal has been called.
+    // Because SQLite statement execution can be re-entrant, we keep track of how many
+    // times we have attempted to attach a cancellation signal to the connection so that
+    // we can ensure that we detach the signal at the right time.
+    private int mCancellationSignalAttachCount;
+
     private static native int nativeOpen(String path, int openFlags, String label,
             boolean enableTrace, boolean enableProfile);
     private static native void nativeClose(int connectionPtr);
@@ -145,6 +153,8 @@
             int connectionPtr, int statementPtr, int windowPtr,
             int startPos, int requiredPos, boolean countAllRows);
     private static native int nativeGetDbLookaside(int connectionPtr);
+    private static native void nativeCancel(int connectionPtr);
+    private static native void nativeResetCancel(int connectionPtr, boolean cancelable);
 
     private SQLiteConnection(SQLiteConnectionPool pool,
             SQLiteDatabaseConfiguration configuration,
@@ -345,11 +355,14 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public void execute(String sql, Object[] bindArgs) {
+    public void execute(String sql, Object[] bindArgs,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -361,7 +374,12 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                nativeExecute(mConnectionPtr, statement.mStatementPtr);
+                attachCancellationSignal(cancellationSignal);
+                try {
+                    nativeExecute(mConnectionPtr, statement.mStatementPtr);
+                } finally {
+                    detachCancellationSignal(cancellationSignal);
+                }
             } finally {
                 releasePreparedStatement(statement);
             }
@@ -378,13 +396,16 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The value of the first column in the first row of the result set
      * as a <code>long</code>, or zero if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public long executeForLong(String sql, Object[] bindArgs) {
+    public long executeForLong(String sql, Object[] bindArgs,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -396,7 +417,12 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                return nativeExecuteForLong(mConnectionPtr, statement.mStatementPtr);
+                attachCancellationSignal(cancellationSignal);
+                try {
+                    return nativeExecuteForLong(mConnectionPtr, statement.mStatementPtr);
+                } finally {
+                    detachCancellationSignal(cancellationSignal);
+                }
             } finally {
                 releasePreparedStatement(statement);
             }
@@ -413,13 +439,16 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The value of the first column in the first row of the result set
      * as a <code>String</code>, or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public String executeForString(String sql, Object[] bindArgs) {
+    public String executeForString(String sql, Object[] bindArgs,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -431,7 +460,12 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                return nativeExecuteForString(mConnectionPtr, statement.mStatementPtr);
+                attachCancellationSignal(cancellationSignal);
+                try {
+                    return nativeExecuteForString(mConnectionPtr, statement.mStatementPtr);
+                } finally {
+                    detachCancellationSignal(cancellationSignal);
+                }
             } finally {
                 releasePreparedStatement(statement);
             }
@@ -449,14 +483,17 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The file descriptor for a shared memory region that contains
      * the value of the first column in the first row of the result set as a BLOB,
      * or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs) {
+    public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -469,9 +506,14 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                int fd = nativeExecuteForBlobFileDescriptor(
-                        mConnectionPtr, statement.mStatementPtr);
-                return fd >= 0 ? ParcelFileDescriptor.adoptFd(fd) : null;
+                attachCancellationSignal(cancellationSignal);
+                try {
+                    int fd = nativeExecuteForBlobFileDescriptor(
+                            mConnectionPtr, statement.mStatementPtr);
+                    return fd >= 0 ? ParcelFileDescriptor.adoptFd(fd) : null;
+                } finally {
+                    detachCancellationSignal(cancellationSignal);
+                }
             } finally {
                 releasePreparedStatement(statement);
             }
@@ -489,12 +531,15 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The number of rows that were changed.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public int executeForChangedRowCount(String sql, Object[] bindArgs) {
+    public int executeForChangedRowCount(String sql, Object[] bindArgs,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -507,8 +552,13 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                return nativeExecuteForChangedRowCount(
-                        mConnectionPtr, statement.mStatementPtr);
+                attachCancellationSignal(cancellationSignal);
+                try {
+                    return nativeExecuteForChangedRowCount(
+                            mConnectionPtr, statement.mStatementPtr);
+                } finally {
+                    detachCancellationSignal(cancellationSignal);
+                }
             } finally {
                 releasePreparedStatement(statement);
             }
@@ -526,12 +576,15 @@
      *
      * @param sql The SQL statement to execute.
      * @param bindArgs The arguments to bind, or null if none.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The row id of the last row that was inserted, or 0 if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public long executeForLastInsertedRowId(String sql, Object[] bindArgs) {
+    public long executeForLastInsertedRowId(String sql, Object[] bindArgs,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -544,8 +597,13 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                return nativeExecuteForLastInsertedRowId(
-                        mConnectionPtr, statement.mStatementPtr);
+                attachCancellationSignal(cancellationSignal);
+                try {
+                    return nativeExecuteForLastInsertedRowId(
+                            mConnectionPtr, statement.mStatementPtr);
+                } finally {
+                    detachCancellationSignal(cancellationSignal);
+                }
             } finally {
                 releasePreparedStatement(statement);
             }
@@ -571,14 +629,17 @@
      * so that it does.  Must be greater than or equal to <code>startPos</code>.
      * @param countAllRows True to count all rows that the query would return
      * regagless of whether they fit in the window.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The number of rows that were counted during query execution.  Might
      * not be all rows in the result set unless <code>countAllRows</code> is true.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
     public int executeForCursorWindow(String sql, Object[] bindArgs,
-            CursorWindow window, int startPos, int requiredPos, boolean countAllRows) {
+            CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -597,14 +658,19 @@
                 throwIfStatementForbidden(statement);
                 bindArguments(statement, bindArgs);
                 applyBlockGuardPolicy(statement);
-                final long result = nativeExecuteForCursorWindow(
-                        mConnectionPtr, statement.mStatementPtr, window.mWindowPtr,
-                        startPos, requiredPos, countAllRows);
-                actualPos = (int)(result >> 32);
-                countedRows = (int)result;
-                filledRows = window.getNumRows();
-                window.setStartPosition(actualPos);
-                return countedRows;
+                attachCancellationSignal(cancellationSignal);
+                try {
+                    final long result = nativeExecuteForCursorWindow(
+                            mConnectionPtr, statement.mStatementPtr, window.mWindowPtr,
+                            startPos, requiredPos, countAllRows);
+                    actualPos = (int)(result >> 32);
+                    countedRows = (int)result;
+                    filledRows = window.getNumRows();
+                    window.setStartPosition(actualPos);
+                    return countedRows;
+                } finally {
+                    detachCancellationSignal(cancellationSignal);
+                }
             } finally {
                 releasePreparedStatement(statement);
             }
@@ -685,6 +751,46 @@
         recyclePreparedStatement(statement);
     }
 
+    private void attachCancellationSignal(CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
+
+            mCancellationSignalAttachCount += 1;
+            if (mCancellationSignalAttachCount == 1) {
+                // Reset cancellation flag before executing the statement.
+                nativeResetCancel(mConnectionPtr, true /*cancelable*/);
+
+                // After this point, onCancel() may be called concurrently.
+                cancellationSignal.setOnCancelListener(this);
+            }
+        }
+    }
+
+    private void detachCancellationSignal(CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            assert mCancellationSignalAttachCount > 0;
+
+            mCancellationSignalAttachCount -= 1;
+            if (mCancellationSignalAttachCount == 0) {
+                // After this point, onCancel() cannot be called concurrently.
+                cancellationSignal.setOnCancelListener(null);
+
+                // Reset cancellation flag after executing the statement.
+                nativeResetCancel(mConnectionPtr, false /*cancelable*/);
+            }
+        }
+    }
+
+    // CancellationSignal.OnCancelListener callback.
+    // This method may be called on a different thread than the executing statement.
+    // However, it will only be called between calls to attachCancellationSignal and
+    // detachCancellationSignal, while a statement is executing.  We can safely assume
+    // that the SQLite connection is still alive.
+    @Override
+    public void onCancel() {
+        nativeCancel(mConnectionPtr);
+    }
+
     private void bindArguments(PreparedStatement statement, Object[] bindArgs) {
         final int count = bindArgs != null ? bindArgs.length : 0;
         if (count != statement.mNumParameters) {
@@ -822,8 +928,8 @@
         long pageCount = 0;
         long pageSize = 0;
         try {
-            pageCount = executeForLong("PRAGMA page_count;", null);
-            pageSize = executeForLong("PRAGMA page_size;", null);
+            pageCount = executeForLong("PRAGMA page_count;", null, null);
+            pageSize = executeForLong("PRAGMA page_size;", null, null);
         } catch (SQLiteException ex) {
             // Ignore.
         }
@@ -834,15 +940,15 @@
         // the main database which we have already described.
         CursorWindow window = new CursorWindow("collectDbStats");
         try {
-            executeForCursorWindow("PRAGMA database_list;", null, window, 0, 0, false);
+            executeForCursorWindow("PRAGMA database_list;", null, window, 0, 0, false, null);
             for (int i = 1; i < window.getNumRows(); i++) {
                 String name = window.getString(i, 1);
                 String path = window.getString(i, 2);
                 pageCount = 0;
                 pageSize = 0;
                 try {
-                    pageCount = executeForLong("PRAGMA " + name + ".page_count;", null);
-                    pageSize = executeForLong("PRAGMA " + name + ".page_size;", null);
+                    pageCount = executeForLong("PRAGMA " + name + ".page_count;", null, null);
+                    pageSize = executeForLong("PRAGMA " + name + ".page_size;", null, null);
                 } catch (SQLiteException ex) {
                     // Ignore.
                 }
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 5469213..236948e 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -18,6 +18,8 @@
 
 import dalvik.system.CloseGuard;
 
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
 import android.database.sqlite.SQLiteDebug.DbStats;
 import android.os.SystemClock;
 import android.util.Log;
@@ -282,13 +284,16 @@
      * @param sql If not null, try to find a connection that already has
      * the specified SQL statement in its prepared statement cache.
      * @param connectionFlags The connection request flags.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The connection that was acquired, never null.
      *
      * @throws IllegalStateException if the pool has been closed.
      * @throws SQLiteException if a database error occurs.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public SQLiteConnection acquireConnection(String sql, int connectionFlags) {
-        return waitForConnection(sql, connectionFlags);
+    public SQLiteConnection acquireConnection(String sql, int connectionFlags,
+            CancellationSignal cancellationSignal) {
+        return waitForConnection(sql, connectionFlags, cancellationSignal);
     }
 
     /**
@@ -497,7 +502,8 @@
     }
 
     // Might throw.
-    private SQLiteConnection waitForConnection(String sql, int connectionFlags) {
+    private SQLiteConnection waitForConnection(String sql, int connectionFlags,
+            CancellationSignal cancellationSignal) {
         final boolean wantPrimaryConnection =
                 (connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0;
 
@@ -505,6 +511,11 @@
         synchronized (mLock) {
             throwIfClosedLocked();
 
+            // Abort if canceled.
+            if (cancellationSignal != null) {
+                cancellationSignal.throwIfCanceled();
+            }
+
             // Try to acquire a connection.
             SQLiteConnection connection = null;
             if (!wantPrimaryConnection) {
@@ -538,6 +549,18 @@
             } else {
                 mConnectionWaiterQueue = waiter;
             }
+
+            if (cancellationSignal != null) {
+                final int nonce = waiter.mNonce;
+                cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
+                    @Override
+                    public void onCancel() {
+                        synchronized (mLock) {
+                            cancelConnectionWaiterLocked(waiter, nonce);
+                        }
+                    }
+                });
+            }
         }
 
         // Park the thread until a connection is assigned or the pool is closed.
@@ -547,7 +570,9 @@
         for (;;) {
             // Detect and recover from connection leaks.
             if (mConnectionLeaked.compareAndSet(true, false)) {
-                wakeConnectionWaitersLocked();
+                synchronized (mLock) {
+                    wakeConnectionWaitersLocked();
+                }
             }
 
             // Wait to be unparked (may already have happened), a timeout, or interruption.
@@ -560,15 +585,16 @@
             synchronized (mLock) {
                 throwIfClosedLocked();
 
-                SQLiteConnection connection = waiter.mAssignedConnection;
-                if (connection != null) {
+                final SQLiteConnection connection = waiter.mAssignedConnection;
+                final RuntimeException ex = waiter.mException;
+                if (connection != null || ex != null) {
+                    if (cancellationSignal != null) {
+                        cancellationSignal.setOnCancelListener(null);
+                    }
                     recycleConnectionWaiterLocked(waiter);
-                    return connection;
-                }
-
-                RuntimeException ex = waiter.mException;
-                if (ex != null) {
-                    recycleConnectionWaiterLocked(waiter);
+                    if (connection != null) {
+                        return connection;
+                    }
                     throw ex; // rethrow!
                 }
 
@@ -585,6 +611,40 @@
     }
 
     // Can't throw.
+    private void cancelConnectionWaiterLocked(ConnectionWaiter waiter, int nonce) {
+        if (waiter.mNonce != nonce) {
+            // Waiter already removed and recycled.
+            return;
+        }
+
+        if (waiter.mAssignedConnection != null || waiter.mException != null) {
+            // Waiter is done waiting but has not woken up yet.
+            return;
+        }
+
+        // Waiter must still be waiting.  Dequeue it.
+        ConnectionWaiter predecessor = null;
+        ConnectionWaiter current = mConnectionWaiterQueue;
+        while (current != waiter) {
+            assert current != null;
+            predecessor = current;
+            current = current.mNext;
+        }
+        if (predecessor != null) {
+            predecessor.mNext = waiter.mNext;
+        } else {
+            mConnectionWaiterQueue = waiter.mNext;
+        }
+
+        // Send the waiter an exception and unpark it.
+        waiter.mException = new OperationCanceledException();
+        LockSupport.unpark(waiter.mThread);
+
+        // Check whether removing this waiter will enable other waiters to make progress.
+        wakeConnectionWaitersLocked();
+    }
+
+    // Can't throw.
     private void logConnectionPoolBusyLocked(long waitMillis, int connectionFlags) {
         final Thread thread = Thread.currentThread();
         StringBuilder msg = new StringBuilder();
@@ -826,6 +886,7 @@
         waiter.mSql = null;
         waiter.mAssignedConnection = null;
         waiter.mException = null;
+        waiter.mNonce += 1;
         mConnectionWaiterPool = waiter;
     }
 
@@ -904,5 +965,6 @@
         public int mConnectionFlags;
         public SQLiteConnection mAssignedConnection;
         public RuntimeException mException;
+        public int mNonce;
     }
 }
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 946300f..82bb23e 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -65,8 +65,7 @@
      * interface. For a query such as: {@code SELECT name, birth, phone FROM
      * myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth,
      * phone) would be in the projection argument and everything from
-     * {@code FROM} onward would be in the params argument. This constructor
-     * has package scope.
+     * {@code FROM} onward would be in the params argument.
      *
      * @param db a reference to a Database object that is already constructed
      *     and opened. This param is not used any longer
@@ -86,8 +85,7 @@
      * interface. For a query such as: {@code SELECT name, birth, phone FROM
      * myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth,
      * phone) would be in the projection argument and everything from
-     * {@code FROM} onward would be in the params argument. This constructor
-     * has package scope.
+     * {@code FROM} onward would be in the params argument.
      *
      * @param editTable the name of the table used for this query
      * @param query the {@link SQLiteQuery} object associated with this cursor object.
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 9cb6480..505f83e 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -16,7 +16,9 @@
 
 package android.database.sqlite;
 
+import android.content.CancellationSignal;
 import android.content.ContentValues;
+import android.content.OperationCanceledException;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
@@ -492,7 +494,7 @@
             boolean exclusive) {
         getThreadSession().beginTransaction(exclusive ? SQLiteSession.TRANSACTION_MODE_EXCLUSIVE :
                 SQLiteSession.TRANSACTION_MODE_IMMEDIATE, transactionListener,
-                getThreadDefaultConnectionFlags(false /*readOnly*/));
+                getThreadDefaultConnectionFlags(false /*readOnly*/), null);
     }
 
     /**
@@ -500,7 +502,7 @@
      * are committed and rolled back.
      */
     public void endTransaction() {
-        getThreadSession().endTransaction();
+        getThreadSession().endTransaction(null);
     }
 
     /**
@@ -597,7 +599,7 @@
     }
 
     private boolean yieldIfContendedHelper(boolean throwIfUnsafe, long sleepAfterYieldDelay) {
-        return getThreadSession().yieldTransaction(sleepAfterYieldDelay, throwIfUnsafe);
+        return getThreadSession().yieldTransaction(sleepAfterYieldDelay, throwIfUnsafe, null);
     }
 
     /**
@@ -935,7 +937,48 @@
             String selection, String[] selectionArgs, String groupBy,
             String having, String orderBy, String limit) {
         return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
-                groupBy, having, orderBy, limit);
+                groupBy, having, orderBy, limit, null);
+    }
+
+    /**
+     * Query the given URL, returning a {@link Cursor} over the result set.
+     *
+     * @param distinct true if you want each row to be unique, false otherwise.
+     * @param table The table name to compile the query against.
+     * @param columns A list of which columns to return. Passing null will
+     *            return all columns, which is discouraged to prevent reading
+     *            data from storage that isn't going to be used.
+     * @param selection A filter declaring which rows to return, formatted as an
+     *            SQL WHERE clause (excluding the WHERE itself). Passing null
+     *            will return all rows for the given table.
+     * @param selectionArgs You may include ?s in selection, which will be
+     *         replaced by the values from selectionArgs, in order that they
+     *         appear in the selection. The values will be bound as Strings.
+     * @param groupBy A filter declaring how to group rows, formatted as an SQL
+     *            GROUP BY clause (excluding the GROUP BY itself). Passing null
+     *            will cause the rows to not be grouped.
+     * @param having A filter declare which row groups to include in the cursor,
+     *            if row grouping is being used, formatted as an SQL HAVING
+     *            clause (excluding the HAVING itself). Passing null will cause
+     *            all row groups to be included, and is required when row
+     *            grouping is not being used.
+     * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
+     *            (excluding the ORDER BY itself). Passing null will use the
+     *            default sort order, which may be unordered.
+     * @param limit Limits the number of rows returned by the query,
+     *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+     * when the query is executed.
+     * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+     * {@link Cursor}s are not synchronized, see the documentation for more details.
+     * @see Cursor
+     */
+    public Cursor query(boolean distinct, String table, String[] columns,
+            String selection, String[] selectionArgs, String groupBy,
+            String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
+        return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
+                groupBy, having, orderBy, limit, cancellationSignal);
     }
 
     /**
@@ -974,12 +1017,55 @@
             boolean distinct, String table, String[] columns,
             String selection, String[] selectionArgs, String groupBy,
             String having, String orderBy, String limit) {
+        return queryWithFactory(cursorFactory, distinct, table, columns, selection,
+                selectionArgs, groupBy, having, orderBy, limit, null);
+    }
+
+    /**
+     * Query the given URL, returning a {@link Cursor} over the result set.
+     *
+     * @param cursorFactory the cursor factory to use, or null for the default factory
+     * @param distinct true if you want each row to be unique, false otherwise.
+     * @param table The table name to compile the query against.
+     * @param columns A list of which columns to return. Passing null will
+     *            return all columns, which is discouraged to prevent reading
+     *            data from storage that isn't going to be used.
+     * @param selection A filter declaring which rows to return, formatted as an
+     *            SQL WHERE clause (excluding the WHERE itself). Passing null
+     *            will return all rows for the given table.
+     * @param selectionArgs You may include ?s in selection, which will be
+     *         replaced by the values from selectionArgs, in order that they
+     *         appear in the selection. The values will be bound as Strings.
+     * @param groupBy A filter declaring how to group rows, formatted as an SQL
+     *            GROUP BY clause (excluding the GROUP BY itself). Passing null
+     *            will cause the rows to not be grouped.
+     * @param having A filter declare which row groups to include in the cursor,
+     *            if row grouping is being used, formatted as an SQL HAVING
+     *            clause (excluding the HAVING itself). Passing null will cause
+     *            all row groups to be included, and is required when row
+     *            grouping is not being used.
+     * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
+     *            (excluding the ORDER BY itself). Passing null will use the
+     *            default sort order, which may be unordered.
+     * @param limit Limits the number of rows returned by the query,
+     *            formatted as LIMIT clause. Passing null denotes no LIMIT clause.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+     * when the query is executed.
+     * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+     * {@link Cursor}s are not synchronized, see the documentation for more details.
+     * @see Cursor
+     */
+    public Cursor queryWithFactory(CursorFactory cursorFactory,
+            boolean distinct, String table, String[] columns,
+            String selection, String[] selectionArgs, String groupBy,
+            String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
         throwIfNotOpen(); // fail fast
         String sql = SQLiteQueryBuilder.buildQueryString(
                 distinct, table, columns, selection, groupBy, having, orderBy, limit);
 
-        return rawQueryWithFactory(
-                cursorFactory, sql, selectionArgs, findEditTable(table));
+        return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
+                findEditTable(table), cancellationSignal);
     }
 
     /**
@@ -1067,7 +1153,25 @@
      * {@link Cursor}s are not synchronized, see the documentation for more details.
      */
     public Cursor rawQuery(String sql, String[] selectionArgs) {
-        return rawQueryWithFactory(null, sql, selectionArgs, null);
+        return rawQueryWithFactory(null, sql, selectionArgs, null, null);
+    }
+
+    /**
+     * Runs the provided SQL and returns a {@link Cursor} over the result set.
+     *
+     * @param sql the SQL query. The SQL string must not be ; terminated
+     * @param selectionArgs You may include ?s in where clause in the query,
+     *     which will be replaced by the values from selectionArgs. The
+     *     values will be bound as Strings.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+     * when the query is executed.
+     * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+     * {@link Cursor}s are not synchronized, see the documentation for more details.
+     */
+    public Cursor rawQuery(String sql, String[] selectionArgs,
+            CancellationSignal cancellationSignal) {
+        return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
     }
 
     /**
@@ -1085,9 +1189,31 @@
     public Cursor rawQueryWithFactory(
             CursorFactory cursorFactory, String sql, String[] selectionArgs,
             String editTable) {
+        return rawQueryWithFactory(cursorFactory, sql, selectionArgs, editTable, null);
+    }
+
+    /**
+     * Runs the provided SQL and returns a cursor over the result set.
+     *
+     * @param cursorFactory the cursor factory to use, or null for the default factory
+     * @param sql the SQL query. The SQL string must not be ; terminated
+     * @param selectionArgs You may include ?s in where clause in the query,
+     *     which will be replaced by the values from selectionArgs. The
+     *     values will be bound as Strings.
+     * @param editTable the name of the first table, which is editable
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+     * when the query is executed.
+     * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+     * {@link Cursor}s are not synchronized, see the documentation for more details.
+     */
+    public Cursor rawQueryWithFactory(
+            CursorFactory cursorFactory, String sql, String[] selectionArgs,
+            String editTable, CancellationSignal cancellationSignal) {
         throwIfNotOpen(); // fail fast
 
-        SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
+        SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
+                cancellationSignal);
         return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
                 selectionArgs);
     }
@@ -1786,7 +1912,7 @@
      */
     void lockPrimaryConnection() {
         getThreadSession().beginTransaction(SQLiteSession.TRANSACTION_MODE_DEFERRED,
-                null, SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY);
+                null, SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY, null);
     }
 
     /**
@@ -1795,7 +1921,7 @@
      * @see #lockPrimaryConnection()
      */
     void unlockPrimaryConnection() {
-        getThreadSession().endTransaction();
+        getThreadSession().endTransaction(null);
     }
 
     @Override
diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
index 52fd1d2..3375e74 100644
--- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
+++ b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
@@ -16,6 +16,7 @@
 
 package android.database.sqlite;
 
+import android.content.CancellationSignal;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 
@@ -28,16 +29,19 @@
     private final SQLiteDatabase mDatabase;
     private final String mEditTable; 
     private final String mSql;
+    private final CancellationSignal mCancellationSignal;
     private SQLiteQuery mQuery;
 
-    public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable) {
+    public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable,
+            CancellationSignal cancellationSignal) {
         mDatabase = db;
         mEditTable = editTable;
         mSql = sql;
+        mCancellationSignal = cancellationSignal;
     }
 
     public Cursor query(CursorFactory factory, String[] selectionArgs) {
-        final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql);
+        final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
         final Cursor cursor;
         try {
             query.bindAllArgsAsStrings(selectionArgs);
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 8194458..9f0edfb 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -16,6 +16,7 @@
 
 package android.database.sqlite;
 
+import android.content.CancellationSignal;
 import android.database.DatabaseUtils;
 
 import java.util.Arrays;
@@ -36,7 +37,8 @@
     private final int mNumParameters;
     private final Object[] mBindArgs;
 
-    SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs) {
+    SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
+            CancellationSignal cancellationSignalForPrepare) {
         mDatabase = db;
         mSql = sql.trim();
 
@@ -54,7 +56,8 @@
                 boolean assumeReadOnly = (n == DatabaseUtils.STATEMENT_SELECT);
                 SQLiteStatementInfo info = new SQLiteStatementInfo();
                 db.getThreadSession().prepare(mSql,
-                        db.getThreadDefaultConnectionFlags(assumeReadOnly), info);
+                        db.getThreadDefaultConnectionFlags(assumeReadOnly),
+                        cancellationSignalForPrepare, info);
                 mReadOnly = info.readOnly;
                 mColumnNames = info.columnNames;
                 mNumParameters = info.numParameters;
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index 17aa886..30e77b5 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -16,6 +16,8 @@
 
 package android.database.sqlite;
 
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
 import android.database.CursorWindow;
 import android.util.Log;
 
@@ -29,8 +31,12 @@
 public final class SQLiteQuery extends SQLiteProgram {
     private static final String TAG = "SQLiteQuery";
 
-    SQLiteQuery(SQLiteDatabase db, String query) {
-        super(db, query, null);
+    private final CancellationSignal mCancellationSignal;
+
+    SQLiteQuery(SQLiteDatabase db, String query, CancellationSignal cancellationSignal) {
+        super(db, query, null, cancellationSignal);
+
+        mCancellationSignal = cancellationSignal;
     }
 
     /**
@@ -44,6 +50,9 @@
      * return regardless of whether they fit in the window.
      * @return Number of rows that were enumerated.  Might not be all rows
      * unless countAllRows is true.
+     *
+     * @throws SQLiteException if an error occurs.
+     * @throws OperationCanceledException if the operation was canceled.
      */
     int fillWindow(CursorWindow window, int startPos, int requiredPos, boolean countAllRows) {
         acquireReference();
@@ -51,7 +60,8 @@
             window.acquireReference();
             try {
                 int numRows = getSession().executeForCursorWindow(getSql(), getBindArgs(),
-                        window, startPos, requiredPos, countAllRows, getConnectionFlags());
+                        window, startPos, requiredPos, countAllRows, getConnectionFlags(),
+                        mCancellationSignal);
                 return numRows;
             } catch (SQLiteDatabaseCorruptException ex) {
                 onCorruption();
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 1b7b398..6f84b5e 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -16,6 +16,8 @@
 
 package android.database.sqlite;
 
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
 import android.database.Cursor;
 import android.database.DatabaseUtils;
 import android.provider.BaseColumns;
@@ -137,8 +139,9 @@
     /**
      * Sets the cursor factory to be used for the query.  You can use
      * one factory for all queries on a database but it is normally
-     * easier to specify the factory when doing this query.  @param
-     * factory the factor to use
+     * easier to specify the factory when doing this query.
+     *
+     * @param factory the factory to use.
      */
     public void setCursorFactory(SQLiteDatabase.CursorFactory factory) {
         mFactory = factory;
@@ -289,7 +292,7 @@
             String selection, String[] selectionArgs, String groupBy,
             String having, String sortOrder) {
         return query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder,
-                null /* limit */);
+                null /* limit */, null /* cancellationSignal */);
     }
 
     /**
@@ -327,6 +330,48 @@
     public Cursor query(SQLiteDatabase db, String[] projectionIn,
             String selection, String[] selectionArgs, String groupBy,
             String having, String sortOrder, String limit) {
+        return query(db, projectionIn, selection, selectionArgs,
+                groupBy, having, sortOrder, limit, null);
+    }
+
+    /**
+     * Perform a query by combining all current settings and the
+     * information passed into this method.
+     *
+     * @param db the database to query on
+     * @param projectionIn A list of which columns to return. Passing
+     *   null will return all columns, which is discouraged to prevent
+     *   reading data from storage that isn't going to be used.
+     * @param selection A filter declaring which rows to return,
+     *   formatted as an SQL WHERE clause (excluding the WHERE
+     *   itself). Passing null will return all rows for the given URL.
+     * @param selectionArgs You may include ?s in selection, which
+     *   will be replaced by the values from selectionArgs, in order
+     *   that they appear in the selection. The values will be bound
+     *   as Strings.
+     * @param groupBy A filter declaring how to group rows, formatted
+     *   as an SQL GROUP BY clause (excluding the GROUP BY
+     *   itself). Passing null will cause the rows to not be grouped.
+     * @param having A filter declare which row groups to include in
+     *   the cursor, if row grouping is being used, formatted as an
+     *   SQL HAVING clause (excluding the HAVING itself).  Passing
+     *   null will cause all row groups to be included, and is
+     *   required when row grouping is not being used.
+     * @param sortOrder How to order the rows, formatted as an SQL
+     *   ORDER BY clause (excluding the ORDER BY itself). Passing null
+     *   will use the default sort order, which may be unordered.
+     * @param limit Limits the number of rows returned by the query,
+     *   formatted as LIMIT clause. Passing null denotes no LIMIT clause.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+     * when the query is executed.
+     * @return a cursor over the result set
+     * @see android.content.ContentResolver#query(android.net.Uri, String[],
+     *      String, String[], String)
+     */
+    public Cursor query(SQLiteDatabase db, String[] projectionIn,
+            String selection, String[] selectionArgs, String groupBy,
+            String having, String sortOrder, String limit, CancellationSignal cancellationSignal) {
         if (mTables == null) {
             return null;
         }
@@ -341,7 +386,8 @@
             // in both the wrapped and original forms.
             String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy,
                     having, sortOrder, limit);
-            validateQuerySql(db, sqlForValidation); // will throw if query is invalid
+            validateQuerySql(db, sqlForValidation,
+                    cancellationSignal); // will throw if query is invalid
         }
 
         String sql = buildQuery(
@@ -353,16 +399,18 @@
         }
         return db.rawQueryWithFactory(
                 mFactory, sql, selectionArgs,
-                SQLiteDatabase.findEditTable(mTables)); // will throw if query is invalid
+                SQLiteDatabase.findEditTable(mTables),
+                cancellationSignal); // will throw if query is invalid
     }
 
     /**
      * Verifies that a SQL SELECT statement is valid by compiling it.
      * If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
      */
-    private void validateQuerySql(SQLiteDatabase db, String sql) {
+    private void validateQuerySql(SQLiteDatabase db, String sql,
+            CancellationSignal cancellationSignal) {
         db.getThreadSession().prepare(sql,
-                db.getThreadDefaultConnectionFlags(true /*readOnly*/), null);
+                db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancellationSignal, null);
     }
 
     /**
diff --git a/core/java/android/database/sqlite/SQLiteSession.java b/core/java/android/database/sqlite/SQLiteSession.java
index a933051..43efb03 100644
--- a/core/java/android/database/sqlite/SQLiteSession.java
+++ b/core/java/android/database/sqlite/SQLiteSession.java
@@ -16,6 +16,8 @@
 
 package android.database.sqlite;
 
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
 import android.database.CursorWindow;
 import android.database.DatabaseUtils;
 import android.os.ParcelFileDescriptor;
@@ -156,8 +158,6 @@
  * triggers may call custom SQLite functions that perform additional queries.
  * </p>
  *
- * TODO: Support timeouts on all possibly blocking operations.
- *
  * @hide
  */
 public final class SQLiteSession {
@@ -280,24 +280,34 @@
      * @param transactionListener The transaction listener, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      *
      * @throws IllegalStateException if {@link #setTransactionSuccessful} has already been
      * called for the current transaction.
+     * @throws SQLiteException if an error occurs.
+     * @throws OperationCanceledException if the operation was canceled.
      *
      * @see #setTransactionSuccessful
      * @see #yieldTransaction
      * @see #endTransaction
      */
     public void beginTransaction(int transactionMode,
-            SQLiteTransactionListener transactionListener, int connectionFlags) {
+            SQLiteTransactionListener transactionListener, int connectionFlags,
+            CancellationSignal cancellationSignal) {
         throwIfTransactionMarkedSuccessful();
-        beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags);
+        beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags,
+                cancellationSignal);
     }
 
     private void beginTransactionUnchecked(int transactionMode,
-            SQLiteTransactionListener transactionListener, int connectionFlags) {
+            SQLiteTransactionListener transactionListener, int connectionFlags,
+            CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
+        }
+
         if (mTransactionStack == null) {
-            acquireConnection(null, connectionFlags); // might throw
+            acquireConnection(null, connectionFlags, cancellationSignal); // might throw
         }
         try {
             // Set up the transaction such that we can back out safely
@@ -306,13 +316,15 @@
                 // Execute SQL might throw a runtime exception.
                 switch (transactionMode) {
                     case TRANSACTION_MODE_IMMEDIATE:
-                        mConnection.execute("BEGIN IMMEDIATE;", null); // might throw
+                        mConnection.execute("BEGIN IMMEDIATE;", null,
+                                cancellationSignal); // might throw
                         break;
                     case TRANSACTION_MODE_EXCLUSIVE:
-                        mConnection.execute("BEGIN EXCLUSIVE;", null); // might throw
+                        mConnection.execute("BEGIN EXCLUSIVE;", null,
+                                cancellationSignal); // might throw
                         break;
                     default:
-                        mConnection.execute("BEGIN;", null); // might throw
+                        mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
                         break;
                 }
             }
@@ -323,7 +335,7 @@
                     transactionListener.onBegin(); // might throw
                 } catch (RuntimeException ex) {
                     if (mTransactionStack == null) {
-                        mConnection.execute("ROLLBACK;", null); // might throw
+                        mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
                     }
                     throw ex;
                 }
@@ -372,20 +384,28 @@
      * This method must be called exactly once for each call to {@link #beginTransaction}.
      * </p>
      *
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+     *
      * @throws IllegalStateException if there is no current transaction.
+     * @throws SQLiteException if an error occurs.
+     * @throws OperationCanceledException if the operation was canceled.
      *
      * @see #beginTransaction
      * @see #setTransactionSuccessful
      * @see #yieldTransaction
      */
-    public void endTransaction() {
+    public void endTransaction(CancellationSignal cancellationSignal) {
         throwIfNoTransaction();
         assert mConnection != null;
 
-        endTransactionUnchecked();
+        endTransactionUnchecked(cancellationSignal);
     }
 
-    private void endTransactionUnchecked() {
+    private void endTransactionUnchecked(CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
+        }
+
         final Transaction top = mTransactionStack;
         boolean successful = top.mMarkedSuccessful && !top.mChildFailed;
 
@@ -414,9 +434,9 @@
         } else {
             try {
                 if (successful) {
-                    mConnection.execute("COMMIT;", null); // might throw
+                    mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
                 } else {
-                    mConnection.execute("ROLLBACK;", null); // might throw
+                    mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
                 }
             } finally {
                 releaseConnection(); // might throw
@@ -467,16 +487,20 @@
      * @param throwIfUnsafe If true, then instead of returning false when no
      * transaction is in progress, a nested transaction is in progress, or when
      * the transaction has already been marked successful, throws {@link IllegalStateException}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return True if the transaction was actually yielded.
      *
      * @throws IllegalStateException if <code>throwIfNested</code> is true and
      * there is no current transaction, there is a nested transaction in progress or
      * if {@link #setTransactionSuccessful} has already been called for the current transaction.
+     * @throws SQLiteException if an error occurs.
+     * @throws OperationCanceledException if the operation was canceled.
      *
      * @see #beginTransaction
      * @see #endTransaction
      */
-    public boolean yieldTransaction(long sleepAfterYieldDelayMillis, boolean throwIfUnsafe) {
+    public boolean yieldTransaction(long sleepAfterYieldDelayMillis, boolean throwIfUnsafe,
+            CancellationSignal cancellationSignal) {
         if (throwIfUnsafe) {
             throwIfNoTransaction();
             throwIfTransactionMarkedSuccessful();
@@ -493,10 +517,16 @@
             return false;
         }
 
-        return yieldTransactionUnchecked(sleepAfterYieldDelayMillis); // might throw
+        return yieldTransactionUnchecked(sleepAfterYieldDelayMillis,
+                cancellationSignal); // might throw
     }
 
-    private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis) {
+    private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis,
+            CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
+        }
+
         if (!mConnectionPool.shouldYieldConnection(mConnection, mConnectionFlags)) {
             return false;
         }
@@ -504,7 +534,7 @@
         final int transactionMode = mTransactionStack.mMode;
         final SQLiteTransactionListener listener = mTransactionStack.mListener;
         final int connectionFlags = mConnectionFlags;
-        endTransactionUnchecked(); // might throw
+        endTransactionUnchecked(cancellationSignal); // might throw
 
         if (sleepAfterYieldDelayMillis > 0) {
             try {
@@ -514,7 +544,8 @@
             }
         }
 
-        beginTransactionUnchecked(transactionMode, listener, connectionFlags); // might throw
+        beginTransactionUnchecked(transactionMode, listener, connectionFlags,
+                cancellationSignal); // might throw
         return true;
     }
 
@@ -535,17 +566,24 @@
      * @param sql The SQL statement to prepare.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @param outStatementInfo The {@link SQLiteStatementInfo} object to populate
      * with information about the statement, or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public void prepare(String sql, int connectionFlags, SQLiteStatementInfo outStatementInfo) {
+    public void prepare(String sql, int connectionFlags, CancellationSignal cancellationSignal,
+            SQLiteStatementInfo outStatementInfo) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        acquireConnection(sql, connectionFlags); // might throw
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
+        }
+
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
             mConnection.prepare(sql, outStatementInfo); // might throw
         } finally {
@@ -560,22 +598,25 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public void execute(String sql, Object[] bindArgs, int connectionFlags) {
+    public void execute(String sql, Object[] bindArgs, int connectionFlags,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return;
         }
 
-        acquireConnection(sql, connectionFlags); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
-            mConnection.execute(sql, bindArgs); // might throw
+            mConnection.execute(sql, bindArgs, cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -588,24 +629,27 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The value of the first column in the first row of the result set
      * as a <code>long</code>, or zero if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public long executeForLong(String sql, Object[] bindArgs, int connectionFlags) {
+    public long executeForLong(String sql, Object[] bindArgs, int connectionFlags,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return 0;
         }
 
-        acquireConnection(sql, connectionFlags); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
-            return mConnection.executeForLong(sql, bindArgs); // might throw
+            return mConnection.executeForLong(sql, bindArgs, cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -618,24 +662,27 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The value of the first column in the first row of the result set
      * as a <code>String</code>, or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public String executeForString(String sql, Object[] bindArgs, int connectionFlags) {
+    public String executeForString(String sql, Object[] bindArgs, int connectionFlags,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return null;
         }
 
-        acquireConnection(sql, connectionFlags); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
-            return mConnection.executeForString(sql, bindArgs); // might throw
+            return mConnection.executeForString(sql, bindArgs, cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -649,26 +696,29 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The file descriptor for a shared memory region that contains
      * the value of the first column in the first row of the result set as a BLOB,
      * or null if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
     public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
-            int connectionFlags) {
+            int connectionFlags, CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return null;
         }
 
-        acquireConnection(sql, connectionFlags); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
-            return mConnection.executeForBlobFileDescriptor(sql, bindArgs); // might throw
+            return mConnection.executeForBlobFileDescriptor(sql, bindArgs,
+                    cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -682,23 +732,27 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The number of rows that were changed.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags) {
+    public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return 0;
         }
 
-        acquireConnection(sql, connectionFlags); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
-            return mConnection.executeForChangedRowCount(sql, bindArgs); // might throw
+            return mConnection.executeForChangedRowCount(sql, bindArgs,
+                    cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -712,23 +766,27 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The row id of the last row that was inserted, or 0 if none.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags) {
+    public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags,
+            CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             return 0;
         }
 
-        acquireConnection(sql, connectionFlags); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
-            return mConnection.executeForLastInsertedRowId(sql, bindArgs); // might throw
+            return mConnection.executeForLastInsertedRowId(sql, bindArgs,
+                    cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -750,15 +808,17 @@
      * regagless of whether they fit in the window.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return The number of rows that were counted during query execution.  Might
      * not be all rows in the result set unless <code>countAllRows</code> is true.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
     public int executeForCursorWindow(String sql, Object[] bindArgs,
             CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
-            int connectionFlags) {
+            int connectionFlags, CancellationSignal cancellationSignal) {
         if (sql == null) {
             throw new IllegalArgumentException("sql must not be null.");
         }
@@ -766,15 +826,16 @@
             throw new IllegalArgumentException("window must not be null.");
         }
 
-        if (executeSpecial(sql, bindArgs, connectionFlags)) {
+        if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
             window.clear();
             return 0;
         }
 
-        acquireConnection(sql, connectionFlags); // might throw
+        acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
         try {
             return mConnection.executeForCursorWindow(sql, bindArgs,
-                    window, startPos, requiredPos, countAllRows); // might throw
+                    window, startPos, requiredPos, countAllRows,
+                    cancellationSignal); // might throw
         } finally {
             releaseConnection(); // might throw
         }
@@ -793,35 +854,45 @@
      * @param bindArgs The arguments to bind, or null if none.
      * @param connectionFlags The connection flags to use if a connection must be
      * acquired by this operation.  Refer to {@link SQLiteConnectionPool}.
+     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
      * @return True if the statement was of a special form that was handled here,
      * false otherwise.
      *
      * @throws SQLiteException if an error occurs, such as a syntax error
      * or invalid number of bind arguments.
+     * @throws OperationCanceledException if the operation was canceled.
      */
-    private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags) {
+    private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
+            CancellationSignal cancellationSignal) {
+        if (cancellationSignal != null) {
+            cancellationSignal.throwIfCanceled();
+        }
+
         final int type = DatabaseUtils.getSqlStatementType(sql);
         switch (type) {
             case DatabaseUtils.STATEMENT_BEGIN:
-                beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags);
+                beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags,
+                        cancellationSignal);
                 return true;
 
             case DatabaseUtils.STATEMENT_COMMIT:
                 setTransactionSuccessful();
-                endTransaction();
+                endTransaction(cancellationSignal);
                 return true;
 
             case DatabaseUtils.STATEMENT_ABORT:
-                endTransaction();
+                endTransaction(cancellationSignal);
                 return true;
         }
         return false;
     }
 
-    private void acquireConnection(String sql, int connectionFlags) {
+    private void acquireConnection(String sql, int connectionFlags,
+            CancellationSignal cancellationSignal) {
         if (mConnection == null) {
             assert mConnectionUseCount == 0;
-            mConnection = mConnectionPool.acquireConnection(sql, connectionFlags); // might throw
+            mConnection = mConnectionPool.acquireConnection(sql, connectionFlags,
+                    cancellationSignal); // might throw
             mConnectionFlags = connectionFlags;
         }
         mConnectionUseCount += 1;
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 4e20da0..b1092d76 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -28,7 +28,7 @@
  */
 public final class SQLiteStatement extends SQLiteProgram {
     SQLiteStatement(SQLiteDatabase db, String sql, Object[] bindArgs) {
-        super(db, sql, bindArgs);
+        super(db, sql, bindArgs, null);
     }
 
     /**
@@ -41,7 +41,7 @@
     public void execute() {
         acquireReference();
         try {
-            getSession().execute(getSql(), getBindArgs(), getConnectionFlags());
+            getSession().execute(getSql(), getBindArgs(), getConnectionFlags(), null);
         } catch (SQLiteDatabaseCorruptException ex) {
             onCorruption();
             throw ex;
@@ -62,7 +62,7 @@
         acquireReference();
         try {
             return getSession().executeForChangedRowCount(
-                    getSql(), getBindArgs(), getConnectionFlags());
+                    getSql(), getBindArgs(), getConnectionFlags(), null);
         } catch (SQLiteDatabaseCorruptException ex) {
             onCorruption();
             throw ex;
@@ -84,7 +84,7 @@
         acquireReference();
         try {
             return getSession().executeForLastInsertedRowId(
-                    getSql(), getBindArgs(), getConnectionFlags());
+                    getSql(), getBindArgs(), getConnectionFlags(), null);
         } catch (SQLiteDatabaseCorruptException ex) {
             onCorruption();
             throw ex;
@@ -105,7 +105,7 @@
         acquireReference();
         try {
             return getSession().executeForLong(
-                    getSql(), getBindArgs(), getConnectionFlags());
+                    getSql(), getBindArgs(), getConnectionFlags(), null);
         } catch (SQLiteDatabaseCorruptException ex) {
             onCorruption();
             throw ex;
@@ -126,7 +126,7 @@
         acquireReference();
         try {
             return getSession().executeForString(
-                    getSql(), getBindArgs(), getConnectionFlags());
+                    getSql(), getBindArgs(), getConnectionFlags(), null);
         } catch (SQLiteDatabaseCorruptException ex) {
             onCorruption();
             throw ex;
@@ -147,7 +147,7 @@
         acquireReference();
         try {
             return getSession().executeForBlobFileDescriptor(
-                    getSql(), getBindArgs(), getConnectionFlags());
+                    getSql(), getBindArgs(), getConnectionFlags(), null);
         } catch (SQLiteDatabaseCorruptException ex) {
             onCorruption();
             throw ex;
diff --git a/libs/rs/rsFifo.cpp b/core/java/android/hardware/ISerialManager.aidl
similarity index 66%
copy from libs/rs/rsFifo.cpp
copy to core/java/android/hardware/ISerialManager.aidl
index 3d5d8c4..74d30f7 100644
--- a/libs/rs/rsFifo.cpp
+++ b/core/java/android/hardware/ISerialManager.aidl
@@ -14,18 +14,16 @@
  * limitations under the License.
  */
 
-#include "rsFifoSocket.h"
-#include "utils/Timers.h"
-#include "utils/StopWatch.h"
+package android.hardware;
 
-using namespace android;
-using namespace android::renderscript;
+import android.os.ParcelFileDescriptor;
 
-Fifo::Fifo() {
+/** @hide */
+interface ISerialManager
+{
+    /* Returns a list of all available serial ports */
+    String[] getSerialPorts();
 
+    /* Returns a file descriptor for the serial port. */
+    ParcelFileDescriptor openSerialPort(String name);
 }
-
-Fifo::~Fifo() {
-
-}
-
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 784bcc5..51a17c1 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -294,7 +294,7 @@
      * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
      * the ground at the device's current location and roughly points East).</li>
      * <li>Y is tangential to the ground at the device's current location and
-     * points towards the magnetic North Pole.</li>
+     * points towards magnetic north.</li>
      * <li>Z points towards the sky and is perpendicular to the ground.</li>
      * </ul>
      *
diff --git a/core/java/android/hardware/SerialManager.java b/core/java/android/hardware/SerialManager.java
new file mode 100644
index 0000000..c5e1c2b
--- /dev/null
+++ b/core/java/android/hardware/SerialManager.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.hardware;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * @hide
+ */
+public class SerialManager {
+    private static final String TAG = "SerialManager";
+
+    private final Context mContext;
+    private final ISerialManager mService;
+
+    /**
+     * {@hide}
+     */
+    public SerialManager(Context context, ISerialManager service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /**
+     * Returns a string array containing the names of available serial ports
+     *
+     * @return names of available serial ports
+     */
+    public String[] getSerialPorts() {
+        try {
+            return mService.getSerialPorts();
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in getSerialPorts", e);
+            return null;
+        }
+    }
+
+    /**
+     * Opens and returns the {@link android.hardware.SerialPort} with the given name.
+     * The speed of the serial port must be one of:
+     * 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600,
+     * 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000,
+     * 1500000, 2000000, 2500000, 3000000, 3500000 or 4000000
+     *
+     * @param name of the serial port
+     * @param speed at which to open the serial port
+     * @return the serial port
+     */
+    public SerialPort openSerialPort(String name, int speed) throws IOException {
+        try {
+            ParcelFileDescriptor pfd = mService.openSerialPort(name);
+            if (pfd != null) {
+                SerialPort port = new SerialPort(name);
+                port.open(pfd, speed);
+                return port;
+            } else {
+                throw new IOException("Could not open serial port " + name);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "exception in UsbManager.openDevice", e);
+        }
+        return null;
+    }
+}
diff --git a/core/java/android/hardware/SerialPort.java b/core/java/android/hardware/SerialPort.java
new file mode 100644
index 0000000..5ef122b
--- /dev/null
+++ b/core/java/android/hardware/SerialPort.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.nio.ByteBuffer;
+
+/**
+ * @hide
+ */
+public class SerialPort {
+
+    private static final String TAG = "SerialPort";
+
+    // used by the JNI code
+    private int mNativeContext;
+    private final String mName;
+    private ParcelFileDescriptor mFileDescriptor;
+
+    /**
+     * SerialPort should only be instantiated by SerialManager
+     * @hide
+     */
+    public SerialPort(String name) {
+        mName = name;
+    }
+
+    /**
+     * SerialPort should only be instantiated by SerialManager
+     * Speed must be one of 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600,
+     * 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000,
+     * 1500000, 2000000, 2500000, 3000000, 3500000, 4000000
+     *
+     * @hide
+     */
+    public void open(ParcelFileDescriptor pfd, int speed) throws IOException {
+        native_open(pfd.getFileDescriptor(), speed);
+        mFileDescriptor = pfd;
+    }
+
+    /**
+     * Closes the serial port
+     */
+    public void close() throws IOException {
+        if (mFileDescriptor != null) {
+            mFileDescriptor.close();
+            mFileDescriptor = null;
+        }
+        native_close();
+    }
+
+    /**
+     * Returns the name of the serial port
+     *
+     * @return the serial port's name
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Reads data into the provided buffer
+     *
+     * @param buffer to read into
+     * @return number of bytes read
+     */
+    public int read(ByteBuffer buffer) throws IOException {
+        if (buffer.isDirect()) {
+            return native_read_direct(buffer, buffer.remaining());
+        } else if (buffer.hasArray()) {
+            return native_read_array(buffer.array(), buffer.remaining());
+        } else {
+            throw new IllegalArgumentException("buffer is not direct and has no array");
+        }
+    }
+
+    /**
+     * Writes data from provided buffer
+     *
+     * @param buffer to write
+     * @param length number of bytes to write
+     */
+    public void write(ByteBuffer buffer, int length) throws IOException {
+        if (buffer.isDirect()) {
+            native_write_direct(buffer, length);
+        } else if (buffer.hasArray()) {
+            native_write_array(buffer.array(), length);
+        } else {
+            throw new IllegalArgumentException("buffer is not direct and has no array");
+        }
+    }
+
+    /**
+     * Sends a stream of zero valued bits for 0.25 to 0.5 seconds
+     */
+    public void sendBreak() {
+        native_send_break();
+    }
+
+    private native void native_open(FileDescriptor pfd, int speed) throws IOException;
+    private native void native_close();
+    private native int native_read_array(byte[] buffer, int length) throws IOException;
+    private native int native_read_direct(ByteBuffer buffer, int length) throws IOException;
+    private native void native_write_array(byte[] buffer, int length) throws IOException;
+    private native void native_write_direct(ByteBuffer buffer, int length) throws IOException;
+    private native void native_send_break();
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a569317..2eef8f4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -142,8 +142,19 @@
      * If an application uses the network in the background, it should listen
      * for this broadcast and stop using the background data if the value is
      * {@code false}.
+     * <p>
+     *
+     * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability
+     *             of background data depends on several combined factors, and
+     *             this broadcast is no longer sent. Instead, when background
+     *             data is unavailable, {@link #getActiveNetworkInfo()} will now
+     *             appear disconnected. During first boot after a platform
+     *             upgrade, this broadcast will be sent once if
+     *             {@link #getBackgroundDataSetting()} was {@code false} before
+     *             the upgrade.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    @Deprecated
     public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
             "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
 
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 21ecc22..fb09ba5 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -49,6 +49,7 @@
     private LinkCapabilities mLinkCapabilities;
     private NetworkInfo mNetworkInfo;
     private InterfaceObserver mInterfaceObserver;
+    private String mHwAddr;
 
     /* For sending events to connectivity service handler */
     private Handler mCsHandler;
@@ -74,15 +75,13 @@
             if (mIface.equals(iface) && mLinkUp != up) {
                 Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
                 mLinkUp = up;
+                mTracker.mNetworkInfo.setIsAvailable(up);
 
                 // use DHCP
                 if (up) {
                     mTracker.reconnect();
                 } else {
-                    NetworkUtils.stopDhcp(mIface);
-                    mTracker.mNetworkInfo.setIsAvailable(false);
-                    mTracker.mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED,
-                                                           null, null);
+                    mTracker.disconnect();
                 }
             }
         }
@@ -104,10 +103,6 @@
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
         mLinkProperties = new LinkProperties();
         mLinkCapabilities = new LinkCapabilities();
-        mLinkUp = false;
-
-        mNetworkInfo.setIsAvailable(false);
-        setTeardownRequested(false);
     }
 
     private void interfaceAdded(String iface) {
@@ -116,7 +111,7 @@
 
         Log.d(TAG, "Adding " + iface);
 
-        synchronized(mIface) {
+        synchronized(this) {
             if(!mIface.isEmpty())
                 return;
             mIface = iface;
@@ -125,21 +120,15 @@
         mNetworkInfo.setIsAvailable(true);
         Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
         msg.sendToTarget();
-
-        runDhcp();
     }
 
-    private void interfaceRemoved(String iface) {
-        if (!iface.equals(mIface))
-            return;
-
-        Log.d(TAG, "Removing " + iface);
+    public void disconnect() {
 
         NetworkUtils.stopDhcp(mIface);
 
         mLinkProperties.clear();
         mNetworkInfo.setIsAvailable(false);
-        mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+        mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
 
         Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
         msg.sendToTarget();
@@ -147,6 +136,21 @@
         msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
         msg.sendToTarget();
 
+        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+        try {
+            service.clearInterfaceAddresses(mIface);
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
+        }
+    }
+
+    private void interfaceRemoved(String iface) {
+        if (!iface.equals(mIface))
+            return;
+
+        Log.d(TAG, "Removing " + iface);
+        disconnect();
         mIface = "";
     }
 
@@ -161,7 +165,7 @@
                 mLinkProperties = dhcpInfoInternal.makeLinkProperties();
                 mLinkProperties.setInterfaceName(mIface);
 
-                mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+                mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
                 Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
                 msg.sendToTarget();
             }
@@ -208,8 +212,15 @@
             for (String iface : ifaces) {
                 if (iface.matches(sIfaceMatch)) {
                     mIface = iface;
+                    service.setInterfaceUp(iface);
                     InterfaceConfiguration config = service.getInterfaceConfig(iface);
                     mLinkUp = config.isActive();
+                    if (config != null && mHwAddr == null) {
+                        mHwAddr = config.getHardwareAddress();
+                        if (mHwAddr != null) {
+                            mNetworkInfo.setExtraInfo(mHwAddr);
+                        }
+                    }
                     reconnect();
                     break;
                 }
@@ -239,9 +250,11 @@
      * Re-enable connectivity to a network after a {@link #teardown()}.
      */
     public boolean reconnect() {
-        mTeardownRequested.set(false);
-        runDhcp();
-        return true;
+        if (mLinkUp) {
+            mTeardownRequested.set(false);
+            runDhcp();
+        }
+        return mLinkUp;
     }
 
     /**
diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl
index a45ec54..31dc965a 100644
--- a/core/java/android/net/INetworkPolicyListener.aidl
+++ b/core/java/android/net/INetworkPolicyListener.aidl
@@ -21,5 +21,6 @@
 
     void onUidRulesChanged(int uid, int uidRules);
     void onMeteredIfacesChanged(in String[] meteredIfaces);
+    void onRestrictBackgroundChanged(boolean restrictBackground);
 
 }
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 633c38e0..442535a 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -43,7 +43,7 @@
     NetworkPolicy[] getNetworkPolicies();
 
     /** Snooze limit on policy matching given template. */
-    void snoozePolicy(in NetworkTemplate template);
+    void snoozeLimit(in NetworkTemplate template);
 
     /** Control if background data is restricted system-wide. */
     void setRestrictBackground(boolean restrictBackground);
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 7286f0d..2f43cb8 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -351,6 +351,18 @@
     }
 
     /**
+     * Set the extraInfo field.
+     * @param extraInfo an optional {@code String} providing addditional network state
+     * information passed up from the lower networking layers.
+     * @hide
+     */
+    public void setExtraInfo(String extraInfo) {
+        synchronized (this) {
+            this.mExtraInfo = extraInfo;
+        }
+    }
+
+    /**
      * Report the reason an attempt to establish connectivity failed,
      * if one is available.
      * @return the reason for failure, or null if not available
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index d9ea700..04cf1a3 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -38,18 +38,25 @@
     public int cycleDay;
     public long warningBytes;
     public long limitBytes;
-    public long lastSnooze;
+    public long lastWarningSnooze;
+    public long lastLimitSnooze;
     public boolean metered;
 
     private static final long DEFAULT_MTU = 1500;
 
-    public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes,
-            long lastSnooze, boolean metered) {
+    public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
+            long limitBytes, boolean metered) {
+        this(template, cycleDay, warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, metered);
+    }
+
+    public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
+            long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered) {
         this.template = checkNotNull(template, "missing NetworkTemplate");
         this.cycleDay = cycleDay;
         this.warningBytes = warningBytes;
         this.limitBytes = limitBytes;
-        this.lastSnooze = lastSnooze;
+        this.lastWarningSnooze = lastWarningSnooze;
+        this.lastLimitSnooze = lastLimitSnooze;
         this.metered = metered;
     }
 
@@ -58,7 +65,8 @@
         cycleDay = in.readInt();
         warningBytes = in.readLong();
         limitBytes = in.readLong();
-        lastSnooze = in.readLong();
+        lastWarningSnooze = in.readLong();
+        lastLimitSnooze = in.readLong();
         metered = in.readInt() != 0;
     }
 
@@ -68,7 +76,8 @@
         dest.writeInt(cycleDay);
         dest.writeLong(warningBytes);
         dest.writeLong(limitBytes);
-        dest.writeLong(lastSnooze);
+        dest.writeLong(lastWarningSnooze);
+        dest.writeLong(lastLimitSnooze);
         dest.writeInt(metered ? 1 : 0);
     }
 
@@ -78,6 +87,13 @@
     }
 
     /**
+     * Test if given measurement is over {@link #warningBytes}.
+     */
+    public boolean isOverWarning(long totalBytes) {
+        return warningBytes != WARNING_DISABLED && totalBytes >= warningBytes;
+    }
+
+    /**
      * Test if given measurement is near enough to {@link #limitBytes} to be
      * considered over-limit.
      */
@@ -88,6 +104,14 @@
         return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes;
     }
 
+    /**
+     * Clear any existing snooze values, setting to {@link #SNOOZE_NEVER}.
+     */
+    public void clearSnooze() {
+        lastWarningSnooze = SNOOZE_NEVER;
+        lastLimitSnooze = SNOOZE_NEVER;
+    }
+
     /** {@inheritDoc} */
     public int compareTo(NetworkPolicy another) {
         if (another == null || another.limitBytes == LIMIT_DISABLED) {
@@ -103,7 +127,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastSnooze, metered);
+        return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastWarningSnooze,
+                lastLimitSnooze, metered);
     }
 
     @Override
@@ -111,8 +136,10 @@
         if (obj instanceof NetworkPolicy) {
             final NetworkPolicy other = (NetworkPolicy) obj;
             return cycleDay == other.cycleDay && warningBytes == other.warningBytes
-                    && limitBytes == other.limitBytes && lastSnooze == other.lastSnooze
-                    && metered == other.metered && Objects.equal(template, other.template);
+                    && limitBytes == other.limitBytes
+                    && lastWarningSnooze == other.lastWarningSnooze
+                    && lastLimitSnooze == other.lastLimitSnooze && metered == other.metered
+                    && Objects.equal(template, other.template);
         }
         return false;
     }
@@ -120,8 +147,9 @@
     @Override
     public String toString() {
         return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", warningBytes="
-                + warningBytes + ", limitBytes=" + limitBytes + ", lastSnooze=" + lastSnooze
-                + ", metered=" + metered;
+                + warningBytes + ", limitBytes=" + limitBytes + ", lastWarningSnooze="
+                + lastWarningSnooze + ", lastLimitSnooze=" + lastLimitSnooze + ", metered="
+                + metered;
     }
 
     public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index e8f60b4..7a1ef66 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -102,6 +102,15 @@
             this.operations = operations;
         }
 
+        public boolean isNegative() {
+            return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
+        }
+
+        public boolean isEmpty() {
+            return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
+                    && operations == 0;
+        }
+
         @Override
         public String toString() {
             final StringBuilder builder = new StringBuilder();
@@ -343,6 +352,7 @@
      * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
      * since operation counts are at data layer.
      */
+    @Deprecated
     public void spliceOperationsFrom(NetworkStats stats) {
         for (int i = 0; i < size; i++) {
             final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]);
@@ -397,7 +407,7 @@
      * Return total of all fields represented by this snapshot object.
      */
     public Entry getTotal(Entry recycle) {
-        return getTotal(recycle, null, UID_ALL);
+        return getTotal(recycle, null, UID_ALL, false);
     }
 
     /**
@@ -405,7 +415,7 @@
      * the requested {@link #uid}.
      */
     public Entry getTotal(Entry recycle, int limitUid) {
-        return getTotal(recycle, null, limitUid);
+        return getTotal(recycle, null, limitUid, false);
     }
 
     /**
@@ -413,7 +423,11 @@
      * the requested {@link #iface}.
      */
     public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
-        return getTotal(recycle, limitIface, UID_ALL);
+        return getTotal(recycle, limitIface, UID_ALL, false);
+    }
+
+    public Entry getTotalIncludingTags(Entry recycle) {
+        return getTotal(recycle, null, UID_ALL, true);
     }
 
     /**
@@ -423,7 +437,8 @@
      * @param limitIface Set of {@link #iface} to include in total; or {@code
      *            null} to include all ifaces.
      */
-    private Entry getTotal(Entry recycle, HashSet<String> limitIface, int limitUid) {
+    private Entry getTotal(
+            Entry recycle, HashSet<String> limitIface, int limitUid, boolean includeTags) {
         final Entry entry = recycle != null ? recycle : new Entry();
 
         entry.iface = IFACE_ALL;
@@ -442,7 +457,7 @@
 
             if (matchesUid && matchesIface) {
                 // skip specific tags, since already counted in TAG_NONE
-                if (tag[i] != TAG_NONE) continue;
+                if (tag[i] != TAG_NONE && !includeTags) continue;
 
                 entry.rxBytes += rxBytes[i];
                 entry.rxPackets += rxPackets[i];
@@ -460,7 +475,7 @@
      * time, and that none of them have disappeared.
      */
     public NetworkStats subtract(NetworkStats right) {
-        return subtract(this, right, null);
+        return subtract(this, right, null, null);
     }
 
     /**
@@ -471,12 +486,12 @@
      * If counters have rolled backwards, they are clamped to {@code 0} and
      * reported to the given {@link NonMonotonicObserver}.
      */
-    public static NetworkStats subtract(
-            NetworkStats left, NetworkStats right, NonMonotonicObserver observer) {
+    public static <C> NetworkStats subtract(
+            NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie) {
         long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
         if (deltaRealtime < 0) {
             if (observer != null) {
-                observer.foundNonMonotonic(left, -1, right, -1);
+                observer.foundNonMonotonic(left, -1, right, -1, cookie);
             }
             deltaRealtime = 0;
         }
@@ -510,7 +525,7 @@
                 if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
                         || entry.txPackets < 0 || entry.operations < 0) {
                     if (observer != null) {
-                        observer.foundNonMonotonic(left, i, right, j);
+                        observer.foundNonMonotonic(left, i, right, j, cookie);
                     }
                     entry.rxBytes = Math.max(entry.rxBytes, 0);
                     entry.rxPackets = Math.max(entry.rxPackets, 0);
@@ -663,8 +678,8 @@
         }
     };
 
-    public interface NonMonotonicObserver {
+    public interface NonMonotonicObserver<C> {
         public void foundNonMonotonic(
-                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex);
+                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
     }
 }
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 8c01331..faf8a3f 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -26,16 +26,18 @@
 import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
 import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
 import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
+import static com.android.internal.util.ArrayUtils.total;
 
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.MathUtils;
 
+import com.android.internal.util.IndentingPrintWriter;
+
 import java.io.CharArrayWriter;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import java.io.PrintWriter;
 import java.net.ProtocolException;
 import java.util.Arrays;
 import java.util.Random;
@@ -74,6 +76,7 @@
     private long[] txBytes;
     private long[] txPackets;
     private long[] operations;
+    private long totalBytes;
 
     public static class Entry {
         public static final long UNKNOWN = -1;
@@ -106,6 +109,12 @@
         if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
         if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
         bucketCount = 0;
+        totalBytes = 0;
+    }
+
+    public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) {
+        this(bucketDuration, existing.estimateResizeBuckets(bucketDuration));
+        recordEntireHistory(existing);
     }
 
     public NetworkStatsHistory(Parcel in) {
@@ -118,6 +127,7 @@
         txPackets = readLongArray(in);
         operations = readLongArray(in);
         bucketCount = bucketStart.length;
+        totalBytes = in.readLong();
     }
 
     /** {@inheritDoc} */
@@ -130,6 +140,7 @@
         writeLongArray(out, txBytes, bucketCount);
         writeLongArray(out, txPackets, bucketCount);
         writeLongArray(out, operations, bucketCount);
+        out.writeLong(totalBytes);
     }
 
     public NetworkStatsHistory(DataInputStream in) throws IOException {
@@ -144,6 +155,7 @@
                 txPackets = new long[bucketStart.length];
                 operations = new long[bucketStart.length];
                 bucketCount = bucketStart.length;
+                totalBytes = total(rxBytes) + total(txBytes);
                 break;
             }
             case VERSION_ADD_PACKETS:
@@ -158,6 +170,7 @@
                 txPackets = readVarLongArray(in);
                 operations = readVarLongArray(in);
                 bucketCount = bucketStart.length;
+                totalBytes = total(rxBytes) + total(txBytes);
                 break;
             }
             default: {
@@ -208,6 +221,13 @@
     }
 
     /**
+     * Return total bytes represented by this history.
+     */
+    public long getTotalBytes() {
+        return totalBytes;
+    }
+
+    /**
      * Return index of bucket that contains or is immediately before the
      * requested time.
      */
@@ -266,13 +286,16 @@
      * distribute across internal buckets, creating new buckets as needed.
      */
     public void recordData(long start, long end, NetworkStats.Entry entry) {
-        if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 || entry.txPackets < 0
-                || entry.operations < 0) {
+        long rxBytes = entry.rxBytes;
+        long rxPackets = entry.rxPackets;
+        long txBytes = entry.txBytes;
+        long txPackets = entry.txPackets;
+        long operations = entry.operations;
+
+        if (entry.isNegative()) {
             throw new IllegalArgumentException("tried recording negative data");
         }
-        if (entry.rxBytes == 0 && entry.rxPackets == 0 && entry.txBytes == 0 && entry.txPackets == 0
-                && entry.operations == 0) {
-            // nothing to record; skip
+        if (entry.isEmpty()) {
             return;
         }
 
@@ -295,21 +318,23 @@
             if (overlap <= 0) continue;
 
             // integer math each time is faster than floating point
-            final long fracRxBytes = entry.rxBytes * overlap / duration;
-            final long fracRxPackets = entry.rxPackets * overlap / duration;
-            final long fracTxBytes = entry.txBytes * overlap / duration;
-            final long fracTxPackets = entry.txPackets * overlap / duration;
-            final long fracOperations = entry.operations * overlap / duration;
+            final long fracRxBytes = rxBytes * overlap / duration;
+            final long fracRxPackets = rxPackets * overlap / duration;
+            final long fracTxBytes = txBytes * overlap / duration;
+            final long fracTxPackets = txPackets * overlap / duration;
+            final long fracOperations = operations * overlap / duration;
 
             addLong(activeTime, i, overlap);
-            addLong(rxBytes, i, fracRxBytes); entry.rxBytes -= fracRxBytes;
-            addLong(rxPackets, i, fracRxPackets); entry.rxPackets -= fracRxPackets;
-            addLong(txBytes, i, fracTxBytes); entry.txBytes -= fracTxBytes;
-            addLong(txPackets, i, fracTxPackets); entry.txPackets -= fracTxPackets;
-            addLong(operations, i, fracOperations); entry.operations -= fracOperations;
+            addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
+            addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets;
+            addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes;
+            addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets;
+            addLong(this.operations, i, fracOperations); operations -= fracOperations;
 
             duration -= overlap;
         }
+
+        totalBytes += entry.rxBytes + entry.txBytes;
     }
 
     /**
@@ -394,6 +419,7 @@
     /**
      * Remove buckets older than requested cutoff.
      */
+    @Deprecated
     public void removeBucketsBefore(long cutoff) {
         int i;
         for (i = 0; i < bucketCount; i++) {
@@ -415,6 +441,8 @@
             if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
             if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
             bucketCount -= i;
+
+            // TODO: subtract removed values from totalBytes
         }
     }
 
@@ -527,19 +555,17 @@
         return (long) (start + (r.nextFloat() * (end - start)));
     }
 
-    public void dump(String prefix, PrintWriter pw, boolean fullHistory) {
-        pw.print(prefix);
+    public void dump(IndentingPrintWriter pw, boolean fullHistory) {
         pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration);
+        pw.increaseIndent();
 
         final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
         if (start > 0) {
-            pw.print(prefix);
-            pw.print("  (omitting "); pw.print(start); pw.println(" buckets)");
+            pw.print("(omitting "); pw.print(start); pw.println(" buckets)");
         }
 
         for (int i = start; i < bucketCount; i++) {
-            pw.print(prefix);
-            pw.print("  bucketStart="); pw.print(bucketStart[i]);
+            pw.print("bucketStart="); pw.print(bucketStart[i]);
             if (activeTime != null) { pw.print(" activeTime="); pw.print(activeTime[i]); }
             if (rxBytes != null) { pw.print(" rxBytes="); pw.print(rxBytes[i]); }
             if (rxPackets != null) { pw.print(" rxPackets="); pw.print(rxPackets[i]); }
@@ -548,12 +574,14 @@
             if (operations != null) { pw.print(" operations="); pw.print(operations[i]); }
             pw.println();
         }
+
+        pw.decreaseIndent();
     }
 
     @Override
     public String toString() {
         final CharArrayWriter writer = new CharArrayWriter();
-        dump("", new PrintWriter(writer), false);
+        dump(new IndentingPrintWriter(writer, "  "), false);
         return writer.toString();
     }
 
@@ -579,6 +607,10 @@
         if (array != null) array[i] += value;
     }
 
+    public int estimateResizeBuckets(long newBucketDuration) {
+        return (int) (size() * getBucketDuration() / newBucketDuration);
+    }
+
     /**
      * Utility methods for interacting with {@link DataInputStream} and
      * {@link DataOutputStream}, mostly dealing with writing partial arrays.
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 418b82f..8ebfd8d 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -18,6 +18,7 @@
 
 import static android.net.ConnectivityManager.TYPE_ETHERNET;
 import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkIdentity.scrubSubscriberId;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
@@ -231,10 +232,13 @@
      * Check if matches Wi-Fi network template.
      */
     private boolean matchesWifi(NetworkIdentity ident) {
-        if (ident.mType == TYPE_WIFI) {
-            return true;
+        switch (ident.mType) {
+            case TYPE_WIFI:
+            case TYPE_WIFI_P2P:
+                return true;
+            default:
+                return false;
         }
-        return false;
     }
 
     /**
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 8bdb669..973fac1 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -44,6 +44,13 @@
      */
     public final static int UNSUPPORTED = -1;
 
+    /** @hide */
+    public static final long KB_IN_BYTES = 1024;
+    /** @hide */
+    public static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
+    /** @hide */
+    public static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
+
     /**
      * Special UID value used when collecting {@link NetworkStatsHistory} for
      * removed applications.
@@ -195,7 +202,7 @@
             // subtract starting values and return delta
             final NetworkStats profilingStop = getDataLayerSnapshotForUid(context);
             final NetworkStats profilingDelta = NetworkStats.subtract(
-                    profilingStop, sActiveProfilingStart, null);
+                    profilingStop, sActiveProfilingStart, null, null);
             sActiveProfilingStart = null;
             return profilingDelta;
         }
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 0fb49bc..defe7aa 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -28,6 +28,7 @@
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.RandomAccess;
 import java.util.Set;
 import libcore.net.UriCodec;
@@ -1716,6 +1717,38 @@
         return (!"false".equals(flag) && !"0".equals(flag));
     }
 
+    /**
+     * Return a normalized representation of this Uri.
+     *
+     * <p>A normalized Uri has a lowercase scheme component.
+     * This aligns the Uri with Android best practices for
+     * intent filtering.
+     *
+     * <p>For example, "HTTP://www.android.com" becomes
+     * "http://www.android.com"
+     *
+     * <p>All URIs received from outside Android (such as user input,
+     * or external sources like Bluetooth, NFC, or the Internet) should
+     * be normalized before they are used to create an Intent.
+     *
+     * <p class="note">This method does <em>not</em> validate bad URI's,
+     * or 'fix' poorly formatted URI's - so do not use it for input validation.
+     * A Uri will always be returned, even if the Uri is badly formatted to
+     * begin with and a scheme component cannot be found.
+     *
+     * @return normalized Uri (never null)
+     * @see {@link android.content.Intent#setData}
+     * @see {@link #setNormalizedData}
+     */
+    public Uri normalize() {
+        String scheme = getScheme();
+        if (scheme == null) return this;  // give up
+        String lowerScheme = scheme.toLowerCase(Locale.US);
+        if (scheme.equals(lowerScheme)) return this;  // no change
+
+        return buildUpon().scheme(lowerScheme).build();
+    }
+
     /** Identifies a null parcelled Uri. */
     private static final int NULL_TYPE_ID = 0;
 
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 0b93ad0..61bc324 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -17,7 +17,6 @@
 package android.nfc;
 
 import android.app.PendingIntent;
-import android.content.ComponentName;
 import android.content.IntentFilter;
 import android.nfc.NdefMessage;
 import android.nfc.Tag;
@@ -44,4 +43,6 @@
     void setForegroundDispatch(in PendingIntent intent,
             in IntentFilter[] filters, in TechListParcel techLists);
     void setForegroundNdefPush(in NdefMessage msg, in INdefPushCallback callback);
+
+    void dispatch(in Tag tag);
 }
diff --git a/core/java/android/nfc/NdefMessage.java b/core/java/android/nfc/NdefMessage.java
index 38bc16d..5df9272 100644
--- a/core/java/android/nfc/NdefMessage.java
+++ b/core/java/android/nfc/NdefMessage.java
@@ -92,9 +92,7 @@
      * @throws FormatException if the data cannot be parsed
      */
     public NdefMessage(byte[] data) throws FormatException {
-        if (data == null) {
-            throw new NullPointerException("null data");
-        }
+        if (data == null) throw new NullPointerException("data is null");
         ByteBuffer buffer = ByteBuffer.wrap(data);
 
         mRecords = NdefRecord.parse(buffer, false);
@@ -112,9 +110,8 @@
      */
     public NdefMessage(NdefRecord record, NdefRecord ... records) {
         // validate
-        if (record == null) {
-            throw new NullPointerException("record cannot be null");
-        }
+        if (record == null) throw new NullPointerException("record cannot be null");
+
         for (NdefRecord r : records) {
             if (r == null) {
                 throw new NullPointerException("record cannot be null");
@@ -147,7 +144,12 @@
 
     /**
      * Get the NDEF Records inside this NDEF Message.<p>
-     * An NDEF Message always has one or more NDEF Records.
+     * An {@link NdefMessage} always has one or more NDEF Records: so the
+     * following code to retrieve the first record is always safe
+     * (no need to check for null or array length >= 1):
+     * <pre>
+     * NdefRecord firstRecord = ndefMessage.getRecords()[0];
+     * </pre>
      *
      * @return array of one or more NDEF records.
      */
@@ -156,7 +158,28 @@
     }
 
     /**
-     * Return this NDEF MEssage as raw bytes.<p>
+     * Return the length of this NDEF Message if it is written to a byte array
+     * with {@link #toByteArray}.<p>
+     * An NDEF Message can be formatted to bytes in different ways
+     * depending on chunking, SR, and ID flags, so the length returned
+     * by this method may not be equal to the length of the original
+     * byte array used to construct this NDEF Message. However it will
+     * always be equal to the length of the byte array produced by
+     * {@link #toByteArray}.
+     *
+     * @return length of this NDEF Message when written to bytes with {@link #toByteArray}
+     * @see #toByteArray
+     */
+    public int getByteArrayLength() {
+        int length = 0;
+        for (NdefRecord r : mRecords) {
+            length += r.getByteLength();
+        }
+        return length;
+    }
+
+    /**
+     * Return this NDEF Message as raw bytes.<p>
      * The NDEF Message is formatted as per the NDEF 1.0 specification,
      * and the byte array is suitable for network transmission or storage
      * in an NFC Forum NDEF compatible tag.<p>
@@ -164,13 +187,10 @@
      * short record (SR) format and omit the identifier field when possible.
      *
      * @return NDEF Message in binary format
+     * @see getByteArrayLength
      */
     public byte[] toByteArray() {
-        int length = 0;
-        for (NdefRecord r : mRecords) {
-            length += r.getByteLength();
-        }
-
+        int length = getByteArrayLength();
         ByteBuffer buffer = ByteBuffer.allocate(length);
 
         for (int i=0; i<mRecords.length; i++) {
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index b4c488b..0e9e8f4 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -16,6 +16,7 @@
 
 package android.nfc;
 
+import android.content.Intent;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -25,6 +26,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Represents an immutable NDEF Record.
@@ -305,9 +307,9 @@
      * @return Android application NDEF record
      */
     public static NdefRecord createApplicationRecord(String packageName) {
-        if (packageName.length() == 0) {
-            throw new IllegalArgumentException("empty package name");
-        }
+        if (packageName == null) throw new NullPointerException("packageName is null");
+        if (packageName.length() == 0) throw new IllegalArgumentException("packageName is empty");
+
         return new NdefRecord(TNF_EXTERNAL_TYPE, RTD_ANDROID_APP, null,
                 packageName.getBytes(Charsets.UTF_8));
     }
@@ -318,32 +320,27 @@
      * Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
      * and {@link #RTD_URI}. This is the most efficient encoding
      * of a URI into NDEF.<p>
+     * The uri parameter will be normalized with
+     * {@link Uri#normalize} to set the scheme to lower case to
+     * follow Android best practices for intent filtering.
+     * However the unchecked exception
+     * {@link IllegalArgumentException} may be thrown if the uri
+     * parameter has serious problems, for example if it is empty, so always
+     * catch this exception if you are passing user-generated data into this
+     * method.<p>
+     *
      * Reference specification: NFCForum-TS-RTD_URI_1.0
      *
      * @param uri URI to encode.
      * @return an NDEF Record containing the URI
-     * @throws IllegalArugmentException if a valid record cannot be created
+     * @throws IllegalArugmentException if the uri is empty or invalid
      */
     public static NdefRecord createUri(Uri uri) {
-        return createUri(uri.toString());
-    }
+        if (uri == null) throw new NullPointerException("uri is null");
 
-    /**
-     * Create a new NDEF Record containing a URI.<p>
-     * Use this method to encode a URI (or URL) into an NDEF Record.<p>
-     * Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
-     * and {@link #RTD_URI}. This is the most efficient encoding
-     * of a URI into NDEF.<p>
-     * Reference specification: NFCForum-TS-RTD_URI_1.0
-     *
-     * @param uriString string URI to encode.
-     * @return an NDEF Record containing the URI
-     * @throws IllegalArugmentException if a valid record cannot be created
-     */
-    public static NdefRecord createUri(String uriString) {
-        if (uriString.length() == 0) {
-            throw new IllegalArgumentException("empty uriString");
-        }
+        uri = uri.normalize();
+        String uriString = uri.toString();
+        if (uriString.length() == 0) throw new IllegalArgumentException("uri is empty");
 
         byte prefix = 0;
         for (int i = 1; i < URI_PREFIX_MAP.length; i++) {
@@ -361,28 +358,72 @@
     }
 
     /**
+     * Create a new NDEF Record containing a URI.<p>
+     * Use this method to encode a URI (or URL) into an NDEF Record.<p>
+     * Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
+     * and {@link #RTD_URI}. This is the most efficient encoding
+     * of a URI into NDEF.<p>
+      * The uriString parameter will be normalized with
+     * {@link Uri#normalize} to set the scheme to lower case to
+     * follow Android best practices for intent filtering.
+     * However the unchecked exception
+     * {@link IllegalArgumentException} may be thrown if the uriString
+     * parameter has serious problems, for example if it is empty, so always
+     * catch this exception if you are passing user-generated data into this
+     * method.<p>
+     *
+     * Reference specification: NFCForum-TS-RTD_URI_1.0
+     *
+     * @param uriString string URI to encode.
+     * @return an NDEF Record containing the URI
+     * @throws IllegalArugmentException if the uriString is empty or invalid
+     */
+    public static NdefRecord createUri(String uriString) {
+        return createUri(Uri.parse(uriString));
+    }
+
+    /**
      * Create a new NDEF Record containing MIME data.<p>
      * Use this method to encode MIME-typed data into an NDEF Record,
      * such as "text/plain", or "image/jpeg".<p>
-     * Expects US-ASCII characters in mimeType. The encoding of the
-     * mimeData depends on the mimeType.<p>
+     * The mimeType parameter will be normalized with
+     * {@link Intent#normalizeMimeType} to follow Android best
+     * practices for intent filtering, for example to force lower-case.
+     * However the unchecked exception
+     * {@link IllegalArgumentException} may be thrown
+     * if the mimeType parameter has serious problems,
+     * for example if it is empty, so always catch this
+     * exception if you are passing user-generated data into this method.
+     * <p>
      * For efficiency, This method might not make an internal copy of the
      * mimeData byte array, so take care not
-     * to re-use the mimeData byte array while still using the returned
+     * to modify the mimeData byte array while still using the returned
      * NdefRecord.
      *
-     * @param mimeType MIME type, expects US-ASCII characters only
+     * @param mimeType a valid MIME type
      * @param mimeData MIME data as bytes
      * @return an NDEF Record containing the MIME-typed data
-     * @throws IllegalArugmentException if a valid record cannot be created
+     * @throws IllegalArugmentException if the mimeType is empty or invalid
+     *
      */
     public static NdefRecord createMime(String mimeType, byte[] mimeData) {
-        if (mimeType.length() == 0) {
-            throw new IllegalArgumentException("empty mimeType");
-        }
+        if (mimeType == null) throw new NullPointerException("mimeType is null");
 
-        return new NdefRecord(TNF_MIME_MEDIA, mimeType.getBytes(Charsets.US_ASCII), null,
-                mimeData);
+        // We only do basic MIME type validation: trying to follow the
+        // RFCs strictly only ends in tears, since there are lots of MIME
+        // types in common use that are not strictly valid as per RFC rules
+        mimeType = Intent.normalizeMimeType(mimeType);
+        if (mimeType.length() == 0) throw new IllegalArgumentException("mimeType is empty");
+        int slashIndex = mimeType.indexOf('/');
+        if (slashIndex == 0) throw new IllegalArgumentException("mimeType must have major type");
+        if (slashIndex == mimeType.length() - 1) {
+            throw new IllegalArgumentException("mimeType must have minor type");
+        }
+        // missing '/' is allowed
+
+        // MIME RFCs suggest ASCII encoding for content-type
+        byte[] typeBytes = mimeType.getBytes(Charsets.US_ASCII);
+        return new NdefRecord(TNF_MIME_MEDIA, typeBytes, null, mimeData);
     }
 
     /**
@@ -391,32 +432,38 @@
      * The data is typed by a domain name (usually your Android package name) and
      * a domain-specific type. This data is packaged into a "NFC Forum External
      * Type" NDEF Record.<p>
-     * Both the domain and type used to construct an external record are case
-     * insensitive, and this implementation will encode all characters to lower
-     * case. Only a subset of ASCII characters are allowed for the domain
-     * and type. There are no restrictions on the payload data.<p>
+     * NFC Forum requires that the domain and type used in an external record
+     * are treated as case insensitive, however Android intent filtering is
+     * always case sensitive. So this method will force the domain and type to
+     * lower-case before creating the NDEF Record.<p>
+     * The unchecked exception {@link IllegalArgumentException} will be thrown
+     * if the domain and type have serious problems, for example if either field
+     * is empty, so always catch this
+     * exception if you are passing user-generated data into this method.<p>
+     * There are no such restrictions on the payload data.<p>
      * For efficiency, This method might not make an internal copy of the
      * data byte array, so take care not
-     * to re-use the data byte array while still using the returned
+     * to modify the data byte array while still using the returned
      * NdefRecord.
      *
      * Reference specification: NFCForum-TS-RTD_1.0
      * @param domain domain-name of issuing organization
      * @param type domain-specific type of data
      * @param data payload as bytes
-     * @throws IllegalArugmentException if a valid record cannot be created
+     * @throws IllegalArugmentException if either domain or type are empty or invalid
      */
     public static NdefRecord createExternal(String domain, String type, byte[] data) {
-        if (domain.length() == 0 || type.length() == 0) {
-            throw new IllegalArgumentException("empty domain or type");
-        }
-        byte[] byteDomain = domain.getBytes(Charsets.US_ASCII);
-        ensureValidDomain(byteDomain);
-        toLowerCase(byteDomain);
-        byte[] byteType = type.getBytes(Charsets.US_ASCII);
-        ensureValidWkt(byteType);
-        toLowerCase(byteType);
+        if (domain == null) throw new NullPointerException("domain is null");
+        if (type == null) throw new NullPointerException("type is null");
 
+        domain = domain.trim().toLowerCase(Locale.US);
+        type = type.trim().toLowerCase(Locale.US);
+
+        if (domain.length() == 0) throw new IllegalArgumentException("domain is empty");
+        if (type.length() == 0) throw new IllegalArgumentException("type is empty");
+
+        byte[] byteDomain = domain.getBytes(Charsets.UTF_8);
+        byte[] byteType = type.getBytes(Charsets.UTF_8);
         byte[] b = new byte[byteDomain.length + 1 + byteType.length];
         System.arraycopy(byteDomain, 0, b, 0, byteDomain.length);
         b[byteDomain.length] = ':';
@@ -574,51 +621,113 @@
     }
 
     /**
-     * Helper to return the NdefRecord as a URI.
-     * TODO: Consider making a member method instead of static
-     * TODO: Consider more validation that this is a URI record
-     * TODO: Make a public API
-     * @hide
+     * Map this record to a MIME type, or return null if it cannot be mapped.<p>
+     * Currently this method considers all {@link #TNF_MIME_MEDIA} records to
+     * be MIME records, as well as some {@link #TNF_WELL_KNOWN} records such as
+     * {@link #RTD_TEXT}. If this is a MIME record then the MIME type as string
+     * is returned, otherwise null is returned.<p>
+     * This method does not perform validation that the MIME type is
+     * actually valid. It always attempts to
+     * return a string containing the type if this is a MIME record.<p>
+     * The returned MIME type will by normalized to lower-case using
+     * {@link Intent#normalizeMimeType}.<p>
+     * The MIME payload can be obtained using {@link #getPayload}.
+     *
+     * @return MIME type as a string, or null if this is not a MIME record
      */
-    public static Uri parseWellKnownUriRecord(NdefRecord record) throws FormatException {
-        byte[] payload = record.getPayload();
-        if (payload.length < 2) {
-            throw new FormatException("Payload is not a valid URI (missing prefix)");
+    public String toMimeType() {
+        switch (mTnf) {
+            case NdefRecord.TNF_WELL_KNOWN:
+                if (Arrays.equals(mType, NdefRecord.RTD_TEXT)) {
+                    return "text/plain";
+                }
+                break;
+            case NdefRecord.TNF_MIME_MEDIA:
+                String mimeType = new String(mType, Charsets.US_ASCII);
+                return Intent.normalizeMimeType(mimeType);
         }
-
-        /*
-         * payload[0] contains the URI Identifier Code, per the
-         * NFC Forum "URI Record Type Definition" section 3.2.2.
-         *
-         * payload[1]...payload[payload.length - 1] contains the rest of
-         * the URI.
-         */
-        int prefixIndex = (payload[0] & 0xff);
-        if (prefixIndex < 0 || prefixIndex >= URI_PREFIX_MAP.length) {
-            throw new FormatException("Payload is not a valid URI (invalid prefix)");
-        }
-        String prefix = URI_PREFIX_MAP[prefixIndex];
-        byte[] fullUri = concat(prefix.getBytes(Charsets.UTF_8),
-                Arrays.copyOfRange(payload, 1, payload.length));
-        return Uri.parse(new String(fullUri, Charsets.UTF_8));
-    }
-
-    private static byte[] concat(byte[]... arrays) {
-        int length = 0;
-        for (byte[] array : arrays) {
-            length += array.length;
-        }
-        byte[] result = new byte[length];
-        int pos = 0;
-        for (byte[] array : arrays) {
-            System.arraycopy(array, 0, result, pos, array.length);
-            pos += array.length;
-        }
-        return result;
+        return null;
     }
 
     /**
-     * Main parsing method.<p>
+     * Map this record to a URI, or return null if it cannot be mapped.<p>
+     * Currently this method considers the following to be URI records:
+     * <ul>
+     * <li>{@link #TNF_ABSOLUTE_URI} records.</li>
+     * <li>{@link #TNF_WELL_KNOWN} with a type of {@link #RTD_URI}.</li>
+     * <li>{@link #TNF_WELL_KNOWN} with a type of {@link #RTD_SMART_POSTER}
+     * and containing a URI record in the NDEF message nested in the payload.
+     * </li>
+     * <li>{@link #TNF_EXTERNAL_TYPE} records.</li>
+     * </ul>
+     * If this is not a URI record by the above rules, then null is returned.<p>
+     * This method does not perform validation that the URI is
+     * actually valid: it always attempts to create and return a URI if
+     * this record appears to be a URI record by the above rules.<p>
+     * The returned URI will be normalized to have a lower case scheme
+     * using {@link Uri#normalize}.<p>
+     *
+     * @return URI, or null if this is not a URI record
+     */
+    public Uri toUri() {
+        return toUri(false);
+    }
+
+    private Uri toUri(boolean inSmartPoster) {
+        switch (mTnf) {
+            case TNF_WELL_KNOWN:
+                if (Arrays.equals(mType, RTD_SMART_POSTER) && !inSmartPoster) {
+                    try {
+                        // check payload for a nested NDEF Message containing a URI
+                        NdefMessage nestedMessage = new NdefMessage(mPayload);
+                        for (NdefRecord nestedRecord : nestedMessage.getRecords()) {
+                            Uri uri = nestedRecord.toUri(true);
+                            if (uri != null) {
+                                return uri;
+                            }
+                        }
+                    } catch (FormatException e) {  }
+                } else if (Arrays.equals(mType, RTD_URI)) {
+                    return parseWktUri().normalize();
+                }
+                break;
+
+            case TNF_ABSOLUTE_URI:
+                Uri uri = Uri.parse(new String(mType, Charsets.UTF_8));
+                return uri.normalize();
+
+            case TNF_EXTERNAL_TYPE:
+                if (inSmartPoster) {
+                    break;
+                }
+                return Uri.parse("vnd.android.nfc://ext/" + new String(mType, Charsets.US_ASCII));
+        }
+        return null;
+    }
+
+    /**
+     * Return complete URI of {@link #TNF_WELL_KNOWN}, {@link #RTD_URI} records.
+     * @return complete URI, or null if invalid
+     */
+    private Uri parseWktUri() {
+        if (mPayload.length < 2) {
+            return null;
+        }
+
+        // payload[0] contains the URI Identifier Code, as per
+        // NFC Forum "URI Record Type Definition" section 3.2.2.
+        int prefixIndex = (mPayload[0] & (byte)0xFF);
+        if (prefixIndex < 0 || prefixIndex >= URI_PREFIX_MAP.length) {
+            return null;
+        }
+        String prefix = URI_PREFIX_MAP[prefixIndex];
+        String suffix = new String(Arrays.copyOfRange(mPayload, 1, mPayload.length),
+                Charsets.UTF_8);
+        return Uri.parse(prefix + suffix);
+    }
+
+    /**
+     * Main record parsing method.<p>
      * Expects NdefMessage to begin immediately, allows trailing data.<p>
      * Currently has strict validation of all fields as per NDEF 1.0
      * specification section 2.5. We will attempt to keep this as strict as
@@ -902,42 +1011,4 @@
         }
         return s;
     }
-
-    /** Ensure valid 'DNS-char' as per RFC2234 */
-    private static void ensureValidDomain(byte[] bs) {
-        for (int i = 0; i < bs.length; i++) {
-            byte b = bs[i];
-            if ((b >= 'A' && b <= 'Z') ||
-                    (b >= 'a' && b <= 'z') ||
-                    (b >= '0' && b <= '9') ||
-                    b == '.' || b == '-') {
-                continue;
-            }
-            throw new IllegalArgumentException("invalid character in domain");
-        }
-    }
-
-    /** Ensure valid 'WKT-char' as per RFC2234 */
-    private static void ensureValidWkt(byte[] bs) {
-        for (int i = 0; i < bs.length; i++) {
-            byte b = bs[i];
-            if ((b >= 'A' && b <= 'Z') ||
-                    (b >= 'a' && b <= 'z') ||
-                    (b >= '0' && b <= '9') ||
-                    b == '(' || b == ')' || b == '+' || b == ',' || b == '-' ||
-                    b == ':' || b == '=' || b == '@' || b == ';' || b == '$' ||
-                    b == '_' || b == '!' || b == '*' || b == '\'' || b == '.') {
-                continue;
-            }
-            throw new IllegalArgumentException("invalid character in type");
-        }
-    }
-
-    private static void toLowerCase(byte[] b) {
-        for (int i = 0; i < b.length; i++) {
-            if (b[i] >= 'A' && b[i] <= 'Z') {
-                b[i] += 0x20;
-            }
-        }
-    }
 }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 53a0341..5176857 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -66,6 +66,9 @@
      * <p>If the tag has an NDEF payload this intent is started before
      * {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither
      * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started.
+     *
+     * <p>The MIME type or data URI of this intent are normalized before dispatch -
+     * so that MIME, URI scheme and URI host are always lower-case.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
@@ -151,9 +154,13 @@
     public static final String EXTRA_TAG = "android.nfc.extra.TAG";
 
     /**
-     * Optional extra containing an array of {@link NdefMessage} present on the discovered tag for
-     * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
-     * {@link #ACTION_TAG_DISCOVERED} intents.
+     * Extra containing an array of {@link NdefMessage} present on the discovered tag.<p>
+     * This extra is mandatory for {@link #ACTION_NDEF_DISCOVERED} intents,
+     * and optional for {@link #ACTION_TECH_DISCOVERED}, and
+     * {@link #ACTION_TAG_DISCOVERED} intents.<p>
+     * When this extra is present there will always be at least one
+     * {@link NdefMessage} element. Most NDEF tags have only one NDEF message,
+     * but we use an array for future compatibility.
      */
     public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
 
@@ -386,10 +393,10 @@
      */
     @Deprecated
     public static NfcAdapter getDefaultAdapter() {
-        // introduce in API version 9 (GB 2.3)
+        // introduced in API version 9 (GB 2.3)
         // deprecated in API version 10 (GB 2.3.3)
         // removed from public API in version 16 (ICS MR2)
-        // will need to maintain this as a hidden API for a while longer...
+        // should maintain as a hidden API for binary compatibility for a little longer
         Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
                 "NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
 
@@ -803,6 +810,7 @@
      * @throws IllegalStateException if the Activity has already been paused
      * @deprecated use {@link #setNdefPushMessage} instead
      */
+    @Deprecated
     public void disableForegroundNdefPush(Activity activity) {
         if (activity == null) {
             throw new NullPointerException();
@@ -875,6 +883,24 @@
     }
 
     /**
+     * Inject a mock NFC tag.<p>
+     * Used for testing purposes.
+     * <p class="note">Requires the
+     * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+     * @hide
+     */
+    public void dispatch(Tag tag) {
+        if (tag == null) {
+            throw new NullPointerException("tag cannot be null");
+        }
+        try {
+            sService.dispatch(tag);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+        }
+    }
+
+    /**
      * @hide
      */
     public INfcAdapterExtras getNfcAdapterExtrasInterface() {
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 9fe0bed..f9b765cb 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -108,14 +108,14 @@
  * <p>
  */
 public final class Tag implements Parcelable {
-    /*package*/ final byte[] mId;
-    /*package*/ final int[] mTechList;
-    /*package*/ final String[] mTechStringList;
-    /*package*/ final Bundle[] mTechExtras;
-    /*package*/ final int mServiceHandle;  // for use by NFC service, 0 indicates a mock
-    /*package*/ final INfcTag mTagService; // interface to NFC service, will be null if mock tag
+    final byte[] mId;
+    final int[] mTechList;
+    final String[] mTechStringList;
+    final Bundle[] mTechExtras;
+    final int mServiceHandle;  // for use by NFC service, 0 indicates a mock
+    final INfcTag mTagService; // interface to NFC service, will be null if mock tag
 
-    /*package*/ int mConnectedTechnology;
+    int mConnectedTechnology;
 
     /**
      * Hidden constructor to be used by NFC service and internal classes.
diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/core/java/android/nfc/tech/BasicTagTechnology.java
index 913ae0e..b6b347c 100644
--- a/core/java/android/nfc/tech/BasicTagTechnology.java
+++ b/core/java/android/nfc/tech/BasicTagTechnology.java
@@ -18,7 +18,6 @@
 
 import android.nfc.ErrorCodes;
 import android.nfc.Tag;
-import android.nfc.TagLostException;
 import android.nfc.TransceiveResult;
 import android.os.RemoteException;
 import android.util.Log;
@@ -28,12 +27,13 @@
 /**
  * A base class for tag technologies that are built on top of transceive().
  */
-/* package */ abstract class BasicTagTechnology implements TagTechnology {
+abstract class BasicTagTechnology implements TagTechnology {
     private static final String TAG = "NFC";
 
-    /*package*/ final Tag mTag;
-    /*package*/ boolean mIsConnected;
-    /*package*/ int mSelectedTechnology;
+    final Tag mTag;
+
+    boolean mIsConnected;
+    int mSelectedTechnology;
 
     BasicTagTechnology(Tag tag, int tech) throws RemoteException {
         mTag = tag;
@@ -139,7 +139,7 @@
         }
     }
     /** Internal transceive */
-    /*package*/ byte[] transceive(byte[] data, boolean raw) throws IOException {
+    byte[] transceive(byte[] data, boolean raw) throws IOException {
         checkConnected();
 
         try {
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 5e9abb7..fd6bed7 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -135,6 +135,8 @@
  * <p>There are a few threading rules that must be followed for this class to
  * work properly:</p>
  * <ul>
+ *     <li>The AsyncTask class must be loaded on the UI thread. This is done
+ *     automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
  *     <li>The task instance must be created on the UI thread.</li>
  *     <li>{@link #execute} must be invoked on the UI thread.</li>
  *     <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 24569fa6..577fc43 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -49,6 +49,7 @@
     private static final boolean FIND_POTENTIAL_LEAKS = false;
     private static final String TAG = "Binder";
 
+    /* mObject is used by native code, do not remove or rename */
     private int mObject;
     private IInterface mOwner;
     private String mDescriptor;
@@ -70,7 +71,35 @@
      * incoming transaction, then its own uid is returned.
      */
     public static final native int getCallingUid();
-    
+
+    /**
+     * Return the original ID of the user assigned to the process that sent you the current
+     * transaction that is being processed. This uid can be used with higher-level system services
+     * to determine its identity and check permissions. If the current thread is not currently
+     * executing an incoming transaction, then its own uid is returned.
+     * <p/>
+     * This value cannot be reset by calls to {@link #clearCallingIdentity()}.
+     * @hide
+     */
+    public static final int getOrigCallingUid() {
+        if (UserId.MU_ENABLED) {
+            return getOrigCallingUidNative();
+        } else {
+            return getCallingUid();
+        }
+    }
+
+    private static final native int getOrigCallingUidNative();
+
+    /**
+     * Utility function to return the user id of the calling process.
+     * @return userId of the calling process, extracted from the callingUid
+     * @hide
+     */
+    public static final int getOrigCallingUser() {
+        return UserId.getUserId(getOrigCallingUid());
+    }
+
     /**
      * Reset the identity of the incoming IPC on the current thread.  This can
      * be useful if, while handling an incoming call, you will be calling
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 88fea91..c106092 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -167,6 +167,8 @@
          * medium density normal size screens unless otherwise indicated).
          * They can still explicitly specify screen support either way with the
          * supports-screens manifest tag.
+         * <li> {@link android.widget.TabHost} will use the new dark tab
+         * background design.
          * </ul>
          */
         public static final int DONUT = 4;
@@ -208,6 +210,13 @@
         
         /**
          * November 2010: Android 2.3
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li> The application's notification icons will be shown on the new
+         * dark status bar background, so must be visible in this situation.
+         * </ul>
          */
         public static final int GINGERBREAD = 9;
         
@@ -224,14 +233,34 @@
          * <ul>
          * <li> The default theme for applications is now dark holographic:
          *      {@link android.R.style#Theme_Holo}.
+         * <li> On large screen devices that do not have a physical menu
+         * button, the soft (compatibility) menu is disabled.
          * <li> The activity lifecycle has changed slightly as per
          * {@link android.app.Activity}.
+         * <li> An application will crash if it does not call through
+         * to the super implementation of its
+         * {@link android.app.Activity#onPause Activity.onPause()} method.
          * <li> When an application requires a permission to access one of
          * its components (activity, receiver, service, provider), this
          * permission is no longer enforced when the application wants to
          * access its own component.  This means it can require a permission
          * on a component that it does not itself hold and still access that
          * component.
+         * <li> {@link android.content.Context#getSharedPreferences
+         * Context.getSharedPreferences()} will not automatically reload
+         * the preferences if they have changed on storage, unless
+         * {@link android.content.Context#MODE_MULTI_PROCESS} is used.
+         * <li> {@link android.view.ViewGroup#setMotionEventSplittingEnabled}
+         * will default to true.
+         * <li> {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH}
+         * is enabled by default on windows.
+         * <li> {@link android.widget.PopupWindow#isSplitTouchEnabled()
+         * PopupWindow.isSplitTouchEnabled()} will return true by default.
+         * <li> {@link android.widget.GridView} and {@link android.widget.ListView}
+         * will use {@link android.view.View#setActivated View.setActivated}
+         * for selected items if they do not implement {@link android.widget.Checkable}.
+         * <li> {@link android.widget.Scroller} will be constructed with
+         * "flywheel" behavior enabled by default.
          * </ul>
          */
         public static final int HONEYCOMB = 11;
@@ -266,13 +295,26 @@
          * preferred over the older screen size buckets and for older devices
          * the appropriate buckets will be inferred from them.</p>
          *
-         * <p>New {@link android.content.pm.PackageManager#FEATURE_SCREEN_PORTRAIT}
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li><p>New {@link android.content.pm.PackageManager#FEATURE_SCREEN_PORTRAIT}
          * and {@link android.content.pm.PackageManager#FEATURE_SCREEN_LANDSCAPE}
-         * features are introduced in this release.  Applications that target
+         * features were introduced in this release.  Applications that target
          * previous platform versions are assumed to require both portrait and
          * landscape support in the device; when targeting Honeycomb MR1 or
          * greater the application is responsible for specifying any specific
          * orientation it requires.</p>
+         * <li><p>{@link android.os.AsyncTask} will use the serial executor
+         * by default when calling {@link android.os.AsyncTask#execute}.</p>
+         * <li><p>{@link android.content.pm.ActivityInfo#configChanges
+         * ActivityInfo.configChanges} will have the
+         * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE} and
+         * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE}
+         * bits set; these need to be cleared for older applications because
+         * some developers have done absolute comparisons against this value
+         * instead of correctly masking the bits they are interested in.
+         * </ul>
          */
         public static final int HONEYCOMB_MR2 = 13;
 
@@ -306,14 +348,31 @@
          * <li> The fadingEdge attribute on views will be ignored (fading edges is no
          * longer a standard part of the UI).  A new requiresFadingEdge attribute allows
          * applications to still force fading edges on for special cases.
+         * <li> {@link android.content.Context#bindService Context.bindService()}
+         * will not automatically add in {@link android.content.Context#BIND_WAIVE_PRIORITY}.
+         * <li> App Widgets will have standard padding automatically added around
+         * them, rather than relying on the padding being baked into the widget itself.
+         * <li> An exception will be thrown if you try to change the type of a
+         * window after it has been added to the window manager.  Previously this
+         * would result in random incorrect behavior.
+         * <li> {@link android.view.animation.AnimationSet} will parse out
+         * the duration, fillBefore, fillAfter, repeatMode, and startOffset
+         * XML attributes that are defined.
+         * <li> {@link android.app.ActionBar#setHomeButtonEnabled
+         * ActionBar.setHomeButtonEnabled()} is false by default.
          * </ul>
          */
         public static final int ICE_CREAM_SANDWICH = 14;
 
         /**
-         * Android 4.0.3.
+         * December 2011: Android 4.0.3.
          */
         public static final int ICE_CREAM_SANDWICH_MR1 = 15;
+
+        /**
+         * Next up on Android!
+         */
+        public static final int JELLY_BEAN = CUR_DEVELOPMENT;
     }
     
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/IServiceManager.java b/core/java/android/os/IServiceManager.java
index 9a5ff47..7b11c28 100644
--- a/core/java/android/os/IServiceManager.java
+++ b/core/java/android/os/IServiceManager.java
@@ -45,7 +45,8 @@
      * Place a new @a service called @a name into the service
      * manager.
      */
-    public void addService(String name, IBinder service) throws RemoteException;
+    public void addService(String name, IBinder service, boolean allowIsolated)
+                throws RemoteException;
 
     /**
      * Return a list of all currently running services.
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index cdf235d..6139296 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -119,7 +119,19 @@
      * Last of application-specific UIDs starting at
      * {@link #FIRST_APPLICATION_UID}.
      */
-    public static final int LAST_APPLICATION_UID = 99999;
+    public static final int LAST_APPLICATION_UID = 19999;
+
+    /**
+     * First uid used for fully isolated sandboxed processes (with no permissions of their own)
+     * @hide
+     */
+    public static final int FIRST_ISOLATED_UID = 99000;
+
+    /**
+     * Last uid used for fully isolated sandboxed processes (with no permissions of their own)
+     * @hide
+     */
+    public static final int LAST_ISOLATED_UID = 99999;
 
     /**
      * Defines a secondary group id for access to the bluetooth hardware.
@@ -576,6 +588,15 @@
     public static final native int myUid();
 
     /**
+     * Returns whether the current process is in an isolated sandbox.
+     * @hide
+     */
+    public static final boolean isIsolated() {
+        int uid = UserId.getAppId(myUid());
+        return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID;
+    }
+
+    /**
      * Returns the UID assigned to a particular user name, or -1 if there is
      * none.  If the given string consists of only numbers, it is converted
      * directly to a uid.
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 1af24f4a..13b8b66 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -69,7 +69,24 @@
      */
     public static void addService(String name, IBinder service) {
         try {
-            getIServiceManager().addService(name, service);
+            getIServiceManager().addService(name, service, false);
+        } catch (RemoteException e) {
+            Log.e(TAG, "error in addService", e);
+        }
+    }
+
+    /**
+     * Place a new @a service called @a name into the service
+     * manager.
+     * 
+     * @param name the name of the new service
+     * @param service the service object
+     * @param allowIsolated set to true to allow isolated sandboxed processes
+     * to access this service
+     */
+    public static void addService(String name, IBinder service, boolean allowIsolated) {
+        try {
+            getIServiceManager().addService(name, service, allowIsolated);
         } catch (RemoteException e) {
             Log.e(TAG, "error in addService", e);
         }
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 2aab0e6..43b5128 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -71,7 +71,8 @@
                 data.enforceInterface(IServiceManager.descriptor);
                 String name = data.readString();
                 IBinder service = data.readStrongBinder();
-                addService(name, service);
+                boolean allowIsolated = data.readInt() != 0;
+                addService(name, service, allowIsolated);
                 return true;
             }
     
@@ -136,13 +137,14 @@
         return binder;
     }
 
-    public void addService(String name, IBinder service)
+    public void addService(String name, IBinder service, boolean allowIsolated)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IServiceManager.descriptor);
         data.writeString(name);
         data.writeStrongBinder(service);
+        data.writeInt(allowIsolated ? 1 : 0);
         mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
         reply.recycle();
         data.recycle();
diff --git a/core/java/android/os/UserId.java b/core/java/android/os/UserId.java
new file mode 100644
index 0000000..0da67d63
--- /dev/null
+++ b/core/java/android/os/UserId.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * @hide
+ */
+public final class UserId {
+    /**
+     * Range of IDs allocated for a user.
+     *
+     * @hide
+     */
+    public static final int PER_USER_RANGE = 100000;
+
+    public static final int USER_ALL = -1;
+
+    /**
+     * Enable multi-user related side effects. Set this to false if there are problems with single
+     * user usecases.
+     * */
+    public static final boolean MU_ENABLED = true;
+
+    /**
+     * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
+     * user.
+     * @hide
+     */
+    public static final boolean isSameUser(int uid1, int uid2) {
+        return getUserId(uid1) == getUserId(uid2);
+    }
+
+    /**
+     * Checks to see if both uids are referring to the same app id, ignoring the user id part of the
+     * uids.
+     * @param uid1 uid to compare
+     * @param uid2 other uid to compare
+     * @return whether the appId is the same for both uids
+     * @hide
+     */
+    public static final boolean isSameApp(int uid1, int uid2) {
+        return getAppId(uid1) == getAppId(uid2);
+    }
+
+    public static final boolean isIsolated(int uid) {
+        uid = getAppId(uid);
+        return uid >= Process.FIRST_ISOLATED_UID && uid <= Process.LAST_ISOLATED_UID;
+    }
+
+    /**
+     * Returns the user id for a given uid.
+     * @hide
+     */
+    public static final int getUserId(int uid) {
+        if (MU_ENABLED) {
+            return uid / PER_USER_RANGE;
+        } else {
+            return 0;
+        }
+    }
+
+    public static final int getCallingUserId() {
+        return getUserId(Binder.getCallingUid());
+    }
+
+    /**
+     * Returns the uid that is composed from the userId and the appId.
+     * @hide
+     */
+    public static final int getUid(int userId, int appId) {
+        if (MU_ENABLED) {
+            return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
+        } else {
+            return appId;
+        }
+    }
+
+    /**
+     * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
+     * @hide
+     */
+    public static final int getAppId(int uid) {
+        return uid % PER_USER_RANGE;
+    }
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index cdb622c..fbf512c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -16,6 +16,7 @@
 
 package android.os.storage;
 
+import android.os.Environment;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -534,6 +535,7 @@
      * @hide
      */
     public String getVolumeState(String mountPoint) {
+         if (mMountService == null) return Environment.MEDIA_REMOVED;
         try {
             return mMountService.getVolumeState(mountPoint);
         } catch (RemoteException e) {
@@ -547,6 +549,7 @@
      * @hide
      */
     public StorageVolume[] getVolumeList() {
+        if (mMountService == null) return new StorageVolume[0];
         try {
             Parcelable[] list = mMountService.getVolumeList();
             if (list == null) return new StorageVolume[0];
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 4e01672..d3ad63d 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -62,6 +62,26 @@
     public static final String ACTION_MTP_SESSION_END = "android.provider.action.MTP_SESSION_END";
 
     /**
+     * The method name used by the media scanner and mtp to tell the media provider to
+     * rescan and reclassify that have become unhidden because of renaming folders or
+     * removing nomedia files
+     * @hide
+     */
+    public static final String UNHIDE_CALL = "unhide";
+
+    /**
+     * This is for internal use by the media scanner only.
+     * Name of the (optional) Uri parameter that determines whether to skip deleting
+     * the file pointed to by the _data column, when deleting the database entry.
+     * The only appropriate value for this parameter is "false", in which case the
+     * delete will be skipped. Note especially that setting this to true, or omitting
+     * the parameter altogether, will perform the default action, which is different
+     * for different types of media.
+     * @hide
+     */
+    public static final String PARAM_DELETE_DATA = "deletedata";
+
+    /**
      * Activity Action: Launch a music player.
      * The activity should be able to play, browse, or manipulate music files stored on the device.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ba9046c..0aad64a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -747,7 +747,7 @@
             Cursor c = null;
             try {
                 c = cp.query(mUri, SELECT_VALUE, NAME_EQ_PLACEHOLDER,
-                             new String[]{name}, null);
+                             new String[]{name}, null, null);
                 if (c == null) {
                     Log.w(TAG, "Can't get key " + name + " from " + mUri);
                     return null;
@@ -1412,7 +1412,7 @@
         public static final int SCREEN_BRIGHTNESS_MODE_MANUAL = 0;
 
         /**
-         * SCREEN_BRIGHTNESS_MODE value for manual mode.
+         * SCREEN_BRIGHTNESS_MODE value for automatic mode.
          */
         public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
 
@@ -1499,6 +1499,12 @@
         public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
 
         /**
+         * Master volume (float in the range 0.0f to 1.0f).
+         * @hide
+         */
+        public static final String VOLUME_MASTER = "volume_master";
+
+        /**
          * Whether the notifications should use the ring volume (value of 1) or a separate
          * notification volume (value of 0). In most cases, users will have this enabled so the
          * notification and ringer volumes will be the same. However, power users can disable this
@@ -1678,6 +1684,13 @@
         public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
 
         /**
+         * Scaling factor for Animator-based animations. This affects both the start delay and
+         * duration of all such animations. Setting to 0 will cause animations to end immediately.
+         * The default value is 1.
+         */
+        public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
+
+        /**
          * Scaling factor for normal window animations. Setting to 0 will disable window
          * animations.
          * @hide
@@ -1823,6 +1836,12 @@
         public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
 
         /**
+         * Whether the lockscreen should be completely disabled.
+         * @hide
+         */
+        public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
+
+        /**
          * URI for the low battery sound file.
          * @hide
          */
@@ -2475,6 +2494,11 @@
             Uri.parse("content://" + AUTHORITY + "/secure");
 
         /**
+         * Whether user has enabled development settings.
+         */
+        public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+
+        /**
          * Whether ADB is enabled.
          */
         public static final String ADB_ENABLED = "adb_enabled";
@@ -4111,17 +4135,38 @@
         /** {@hide} */
         public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval";
         /** {@hide} */
-        public static final String NETSTATS_PERSIST_THRESHOLD = "netstats_persist_threshold";
+        public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age";
         /** {@hide} */
-        public static final String NETSTATS_NETWORK_BUCKET_DURATION = "netstats_network_bucket_duration";
+        public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
         /** {@hide} */
-        public static final String NETSTATS_NETWORK_MAX_HISTORY = "netstats_network_max_history";
+        public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
+
+        /** {@hide} */
+        public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";
+        /** {@hide} */
+        public static final String NETSTATS_DEV_PERSIST_BYTES = "netstats_dev_persist_bytes";
+        /** {@hide} */
+        public static final String NETSTATS_DEV_ROTATE_AGE = "netstats_dev_rotate_age";
+        /** {@hide} */
+        public static final String NETSTATS_DEV_DELETE_AGE = "netstats_dev_delete_age";
+
         /** {@hide} */
         public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration";
         /** {@hide} */
-        public static final String NETSTATS_UID_MAX_HISTORY = "netstats_uid_max_history";
+        public static final String NETSTATS_UID_PERSIST_BYTES = "netstats_uid_persist_bytes";
         /** {@hide} */
-        public static final String NETSTATS_TAG_MAX_HISTORY = "netstats_tag_max_history";
+        public static final String NETSTATS_UID_ROTATE_AGE = "netstats_uid_rotate_age";
+        /** {@hide} */
+        public static final String NETSTATS_UID_DELETE_AGE = "netstats_uid_delete_age";
+
+        /** {@hide} */
+        public static final String NETSTATS_UID_TAG_BUCKET_DURATION = "netstats_uid_tag_bucket_duration";
+        /** {@hide} */
+        public static final String NETSTATS_UID_TAG_PERSIST_BYTES = "netstats_uid_tag_persist_bytes";
+        /** {@hide} */
+        public static final String NETSTATS_UID_TAG_ROTATE_AGE = "netstats_uid_tag_rotate_age";
+        /** {@hide} */
+        public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age";
 
         /** Preferred NTP server. {@hide} */
         public static final String NTP_SERVER = "ntp_server";
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index c184c11..a52e2ba 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -109,6 +109,9 @@
             for (int i = 0; i < spans.length; i++) {
                 int startInPara = spanned.getSpanStart(spans[i]) - start;
                 int endInPara = spanned.getSpanEnd(spans[i]) - start;
+                // The span interval may be larger and must be restricted to [start, end[
+                if (startInPara < 0) startInPara = 0;
+                if (endInPara > len) endInPara = len;
                 for (int j = startInPara; j < endInPara; j++) {
                     mChars[j] = '\uFFFC';
                 }
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index e5c1e5b..ae41eab 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -17,13 +17,10 @@
 package android.text;
 
 
-import java.util.Locale;
-
 import android.util.LocaleUtil;
 
 /**
  * Some objects that implement TextDirectionHeuristic.
- * @hide
  */
 public class TextDirectionHeuristics {
 
@@ -74,9 +71,8 @@
      * Computes the text direction based on an algorithm.  Subclasses implement
      * {@link #defaultIsRtl} to handle cases where the algorithm cannot determine the
      * direction from the text alone.
-     * @hide
      */
-    public static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristic {
+    private static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristic {
         private final TextDirectionAlgorithm mAlgorithm;
 
         public TextDirectionHeuristicImpl(TextDirectionAlgorithm algorithm) {
@@ -157,13 +153,11 @@
     /**
      * Interface for an algorithm to guess the direction of a paragraph of text.
      *
-     * @hide
      */
-    public static interface TextDirectionAlgorithm {
+    private static interface TextDirectionAlgorithm {
         /**
          * Returns whether the range of text is RTL according to the algorithm.
          *
-         * @hide
          */
         TriState checkRtl(char[] text, int start, int count);
     }
@@ -173,9 +167,8 @@
      * the paragraph direction.  This is the standard Unicode Bidirectional
      * algorithm.
      *
-     * @hide
      */
-    public static class FirstStrong implements TextDirectionAlgorithm {
+    private static class FirstStrong implements TextDirectionAlgorithm {
         @Override
         public TriState checkRtl(char[] text, int start, int count) {
             TriState result = TriState.UNKNOWN;
@@ -196,9 +189,8 @@
      * character (e.g. excludes LRE, LRO, RLE, RLO) to determine the
      * direction of text.
      *
-     * @hide
      */
-    public static class AnyStrong implements TextDirectionAlgorithm {
+    private static class AnyStrong implements TextDirectionAlgorithm {
         private final boolean mLookForRtl;
 
         @Override
@@ -239,7 +231,7 @@
     /**
      * Algorithm that uses the Locale direction to force the direction of a paragraph.
      */
-    public static class TextDirectionHeuristicLocale extends TextDirectionHeuristicImpl {
+    private static class TextDirectionHeuristicLocale extends TextDirectionHeuristicImpl {
 
         public TextDirectionHeuristicLocale() {
             super(null);
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 95a3cdc..43dfc81 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1325,7 +1325,11 @@
                 sb.append("&amp;"); //$NON-NLS-1$
                 break;
             case '\'':
-                sb.append("&apos;"); //$NON-NLS-1$
+                //http://www.w3.org/TR/xhtml1
+                // The named character reference &apos; (the apostrophe, U+0027) was introduced in
+                // XML 1.0 but does not appear in HTML. Authors should therefore use &#39; instead
+                // of &apos; to work as expected in HTML 4 user agents.
+                sb.append("&#39;"); //$NON-NLS-1$
                 break;
             case '"':
                 sb.append("&quot;"); //$NON-NLS-1$
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index b4445ca..e9b0d32 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -481,6 +481,9 @@
      * @throws android.util.TimeFormatException if s cannot be parsed.
      */
      public boolean parse3339(String s) {
+         if (s == null) {
+             throw new NullPointerException("time string is null");
+         }
          if (nativeParse3339(s)) {
              timezone = TIMEZONE_UTC;
              return true;
diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java
index 8594852..318149a 100644
--- a/core/java/android/text/method/KeyListener.java
+++ b/core/java/android/text/method/KeyListener.java
@@ -22,7 +22,7 @@
 
 /**
  * Interface for converting text key events into edit operations on an
- * Editable class.  Note that for must cases this interface has been
+ * Editable class.  Note that for most cases this interface has been
  * superceded by general soft input methods as defined by
  * {@link android.view.inputmethod.InputMethod}; it should only be used
  * for cases where an application has its own on-screen keypad and also wants
diff --git a/core/java/android/text/method/TransformationMethod.java b/core/java/android/text/method/TransformationMethod.java
index 9f51c2a..b542109 100644
--- a/core/java/android/text/method/TransformationMethod.java
+++ b/core/java/android/text/method/TransformationMethod.java
@@ -18,7 +18,6 @@
 
 import android.graphics.Rect;
 import android.view.View;
-import android.widget.TextView;
 
 /**
  * TextView uses TransformationMethods to do things like replacing the
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 0f26a34..5dc206f 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -25,6 +25,7 @@
 import android.text.ParcelableSpan;
 import android.text.TextPaint;
 import android.text.TextUtils;
+import android.util.Log;
 import android.widget.TextView;
 
 import java.util.Arrays;
@@ -114,7 +115,7 @@
      * @param context Context for the application
      * @param locale locale Locale of the suggestions
      * @param suggestions Suggestions for the string under the span. Only the first up to
-     * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered.
+     * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered. Null values not permitted.
      * @param flags Additional flags indicating how this span is handled in TextView
      * @param notificationTargetClass if not null, this class will get notified when the user
      * selects one of the suggestions.
@@ -124,10 +125,13 @@
         final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length);
         mSuggestions = Arrays.copyOf(suggestions, N);
         mFlags = flags;
-        if (context != null && locale == null) {
+        if (locale != null) {
+            mLocaleString = locale.toString();
+        } else if (context != null) {
             mLocaleString = context.getResources().getConfiguration().locale.toString();
         } else {
-            mLocaleString = locale.toString();
+            Log.e("SuggestionSpan", "No locale or context specified in SuggestionSpan constructor");
+            mLocaleString = "";
         }
 
         if (notificationTargetClass != null) {
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 519b980..a43d36c 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -57,6 +57,13 @@
     public static final int DENSITY_XHIGH = 320;
 
     /**
+     * Standard quantized DPI for extra-extra-high-density screens.  Applications
+     * should not generally worry about this density; relying on XHIGH graphics
+     * being scaled up to it should be sufficient for almost all cases.
+     */
+    public static final int DENSITY_XXHIGH = 480;
+
+    /**
      * The reference density used throughout the system.
      */
     public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 1ec8be6..630e5f3 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -19,56 +19,50 @@
 import com.android.internal.util.ArrayUtils;
 
 /**
- * SparseArrays map longs to Objects.  Unlike a normal array of Objects,
+ * SparseArray mapping longs to Objects.  Unlike a normal array of Objects,
  * there can be gaps in the indices.  It is intended to be more efficient
  * than using a HashMap to map Longs to Objects.
- *
- * @hide
  */
-public class LongSparseArray<E> {
+public class LongSparseArray<E> implements Cloneable {
     private static final Object DELETED = new Object();
     private boolean mGarbage = false;
 
+    private long[] mKeys;
+    private Object[] mValues;
+    private int mSize;
+
     /**
-     * Creates a new SparseArray containing no mappings.
+     * Creates a new LongSparseArray containing no mappings.
      */
     public LongSparseArray() {
         this(10);
     }
 
     /**
-     * Creates a new SparseArray containing no mappings that will not
+     * Creates a new LongSparseArray containing no mappings that will not
      * require any additional memory allocation to store the specified
      * number of mappings.
      */
     public LongSparseArray(int initialCapacity) {
-        initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+        initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
 
         mKeys = new long[initialCapacity];
         mValues = new Object[initialCapacity];
         mSize = 0;
     }
-    
-    /**
-     * @return A copy of all keys contained in the sparse array.
-     */
-    public long[] getKeys() {
-        int length = mKeys.length;
-        long[] result = new long[length];
-        System.arraycopy(mKeys, 0, result, 0, length);
-        return result;
-    }
-    
-    /**
-     * Sets all supplied keys to the given unique value.
-     * @param keys Keys to set
-     * @param uniqueValue Value to set all supplied keys to
-     */
-    public void setValues(long[] keys, E uniqueValue) {
-        int length = keys.length;
-        for (int i = 0; i < length; i++) {
-            put(keys[i], uniqueValue);
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public LongSparseArray<E> clone() {
+        LongSparseArray<E> clone = null;
+        try {
+            clone = (LongSparseArray<E>) super.clone();
+            clone.mKeys = mKeys.clone();
+            clone.mValues = mValues.clone();
+        } catch (CloneNotSupportedException cnse) {
+            /* ignore */
         }
+        return clone;
     }
 
     /**
@@ -83,6 +77,7 @@
      * Gets the Object mapped from the specified key, or the specified Object
      * if no such mapping has been made.
      */
+    @SuppressWarnings("unchecked")
     public E get(long key, E valueIfKeyNotFound) {
         int i = binarySearch(mKeys, 0, mSize, key);
 
@@ -114,6 +109,16 @@
         delete(key);
     }
 
+    /**
+     * Removes the mapping at the specified index.
+     */
+    public void removeAt(int index) {
+        if (mValues[index] != DELETED) {
+            mValues[index] = DELETED;
+            mGarbage = true;
+        }
+    }
+
     private void gc() {
         // Log.e("SparseArray", "gc start with " + mSize);
 
@@ -129,6 +134,7 @@
                 if (i != o) {
                     keys[o] = keys[i];
                     values[o] = val;
+                    values[i] = null;
                 }
 
                 o++;
@@ -168,7 +174,7 @@
             }
 
             if (mSize >= mKeys.length) {
-                int n = ArrayUtils.idealIntArraySize(mSize + 1);
+                int n = ArrayUtils.idealLongArraySize(mSize + 1);
 
                 long[] nkeys = new long[n];
                 Object[] nvalues = new Object[n];
@@ -194,7 +200,7 @@
     }
 
     /**
-     * Returns the number of key-value mappings that this SparseArray
+     * Returns the number of key-value mappings that this LongSparseArray
      * currently stores.
      */
     public int size() {
@@ -208,7 +214,7 @@
     /**
      * Given an index in the range <code>0...size()-1</code>, returns
      * the key from the <code>index</code>th key-value mapping that this
-     * SparseArray stores.
+     * LongSparseArray stores.
      */
     public long keyAt(int index) {
         if (mGarbage) {
@@ -221,8 +227,9 @@
     /**
      * Given an index in the range <code>0...size()-1</code>, returns
      * the value from the <code>index</code>th key-value mapping that this
-     * SparseArray stores.
+     * LongSparseArray stores.
      */
+    @SuppressWarnings("unchecked")
     public E valueAt(int index) {
         if (mGarbage) {
             gc();
@@ -234,7 +241,7 @@
     /**
      * Given an index in the range <code>0...size()-1</code>, sets a new
      * value for the <code>index</code>th key-value mapping that this
-     * SparseArray stores.
+     * LongSparseArray stores.
      */
     public void setValueAt(int index, E value) {
         if (mGarbage) {
@@ -278,7 +285,7 @@
     }
 
     /**
-     * Removes all key-value mappings from this SparseArray.
+     * Removes all key-value mappings from this LongSparseArray.
      */
     public void clear() {
         int n = mSize;
@@ -308,7 +315,7 @@
 
         int pos = mSize;
         if (pos >= mKeys.length) {
-            int n = ArrayUtils.idealIntArraySize(pos + 1);
+            int n = ArrayUtils.idealLongArraySize(pos + 1);
 
             long[] nkeys = new long[n];
             Object[] nvalues = new Object[n];
@@ -345,20 +352,4 @@
         else
             return ~high;
     }
-
-    private void checkIntegrity() {
-        for (int i = 1; i < mSize; i++) {
-            if (mKeys[i] <= mKeys[i - 1]) {
-                for (int j = 0; j < mSize; j++) {
-                    Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
-                }
-
-                throw new RuntimeException();
-            }
-        }
-    }
-
-    private long[] mKeys;
-    private Object[] mValues;
-    private int mSize;
-}
\ No newline at end of file
+}
diff --git a/core/java/android/view/AccessibilityNodeInfoCache.java b/core/java/android/view/AccessibilityNodeInfoCache.java
new file mode 100644
index 0000000..244a491
--- /dev/null
+++ b/core/java/android/view/AccessibilityNodeInfoCache.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.util.LongSparseArray;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+/**
+ * Simple cache for AccessibilityNodeInfos. The cache is mapping an
+ * accessibility id to an info. The cache allows storing of
+ * <code>null</code> values. It also tracks accessibility events
+ * and invalidates accordingly.
+ *
+ * @hide
+ */
+public class AccessibilityNodeInfoCache {
+
+    private final boolean ENABLED = true;
+
+    /**
+     * @return A new <strong>not synchronized</strong> AccessibilityNodeInfoCache.
+     */
+    public static AccessibilityNodeInfoCache newAccessibilityNodeInfoCache() {
+        return new AccessibilityNodeInfoCache();
+    }
+
+    /**
+     * @return A new <strong>synchronized</strong> AccessibilityNodeInfoCache.
+     */
+    public static AccessibilityNodeInfoCache newSynchronizedAccessibilityNodeInfoCache() {
+        return new AccessibilityNodeInfoCache() {
+            private final Object mLock = new Object();
+
+            @Override
+            public void clear() {
+                synchronized(mLock) {
+                    super.clear();
+                }
+            }
+
+            @Override
+            public AccessibilityNodeInfo get(long accessibilityNodeId) {
+                synchronized(mLock) {
+                    return super.get(accessibilityNodeId);
+                }
+            }
+
+            @Override
+            public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
+                synchronized(mLock) {
+                   super.put(accessibilityNodeId, info);
+                }
+            }
+
+            @Override
+            public void remove(long accessibilityNodeId) {
+                synchronized(mLock) {
+                   super.remove(accessibilityNodeId);
+                }
+            }
+        };
+    }
+
+    private final LongSparseArray<AccessibilityNodeInfo> mCacheImpl;
+
+    private AccessibilityNodeInfoCache() {
+        if (ENABLED) {
+            mCacheImpl = new LongSparseArray<AccessibilityNodeInfo>();
+        } else {
+            mCacheImpl = null;
+        }
+    }
+
+    /**
+     * The cache keeps track of {@link AccessibilityEvent}s and invalidates
+     * cached nodes as appropriate.
+     *
+     * @param event An event.
+     */
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        final int eventType = event.getEventType();
+        switch (eventType) {
+            case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
+            case AccessibilityEvent.TYPE_VIEW_SCROLLED:
+                clear();
+                break;
+            case AccessibilityEvent.TYPE_VIEW_FOCUSED:
+            case AccessibilityEvent.TYPE_VIEW_SELECTED:
+            case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
+            case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
+                final long accessibilityNodeId = event.getSourceNodeId();
+                remove(accessibilityNodeId);
+                break;
+        }
+    }
+
+    /**
+     * Gets a cached {@link AccessibilityNodeInfo} given its accessibility node id.
+     *
+     * @param accessibilityNodeId The info accessibility node id.
+     * @return The cached {@link AccessibilityNodeInfo} or null if such not found.
+     */
+    public AccessibilityNodeInfo get(long accessibilityNodeId) {
+        if (ENABLED) {
+            return mCacheImpl.get(accessibilityNodeId);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Caches an {@link AccessibilityNodeInfo} given its accessibility node id.
+     *
+     * @param accessibilityNodeId The info accessibility node id.
+     * @param info The {@link AccessibilityNodeInfo} to cache.
+     */
+    public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
+        if (ENABLED) {
+            mCacheImpl.put(accessibilityNodeId, info);
+        }
+    }
+
+    /**
+     * Returns whether the cache contains an accessibility node id key.
+     *
+     * @param accessibilityNodeId The key for which to check.
+     * @return True if the key is in the cache.
+     */
+    public boolean containsKey(long accessibilityNodeId) {
+        if (ENABLED) {
+            return (mCacheImpl.indexOfKey(accessibilityNodeId) >= 0);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Removes a cached {@link AccessibilityNodeInfo}.
+     *
+     * @param accessibilityNodeId The info accessibility node id.
+     */
+    public void remove(long accessibilityNodeId) {
+        if (ENABLED) {
+            mCacheImpl.remove(accessibilityNodeId);
+        }
+    }
+
+    /**
+     * Clears the cache.
+     */
+    public void clear() {
+        if (ENABLED) {
+            mCacheImpl.clear();
+        }
+    }
+}
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index 34e7d4d..0349a2b 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -18,9 +18,15 @@
 
 
 /**
- * Represents a contextual mode of the user interface. Action modes can be used for
- * modal interactions with content and replace parts of the normal UI until finished.
- * Examples of good action modes include selection modes, search, content editing, etc.
+ * Represents a contextual mode of the user interface. Action modes can be used to provide
+ * alternative interaction modes and replace parts of the normal UI until finished.
+ * Examples of good action modes include text selection and contextual actions.
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about how to provide contextual actions with {@code ActionMode},
+ * read the <a href="{@docRoot}guide/topics/ui/menu.html#context-menu">Menus</a>
+ * developer guide.</p>
+ * </div>
  */
 public abstract class ActionMode {
     private Object mTag;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 63de128..3e2d7fc 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -26,13 +26,25 @@
 import android.util.Log;
 
 /**
- * Coodinates animations and drawing for UI on a particular thread.
+ * Coordinates animations and drawing for UI on a particular thread.
+ *
+ * This object is thread-safe.  Other threads can add and remove listeners
+ * or schedule work to occur at a later time on the UI thread.
+ *
+ * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver}
+ * can only be accessed from the UI thread so operations that touch the event receiver
+ * are posted to the UI thread if needed.
+ *
  * @hide
  */
 public final class Choreographer extends Handler {
     private static final String TAG = "Choreographer";
     private static final boolean DEBUG = false;
 
+    // Amount of time in ms to wait before actually disposing of the display event
+    // receiver after all listeners have been removed.
+    private static final long DISPOSE_RECEIVER_DELAY = 200;
+
     // The default amount of time in ms between animation frames.
     // When vsync is not enabled, we want to have some idea of how long we should
     // wait before posting the next animation message.  It is important that the
@@ -44,7 +56,7 @@
     private static final long DEFAULT_FRAME_DELAY = 10;
 
     // The number of milliseconds between animation frames.
-    private static long sFrameDelay = DEFAULT_FRAME_DELAY;
+    private static volatile long sFrameDelay = DEFAULT_FRAME_DELAY;
 
     // Thread local storage for the choreographer.
     private static final ThreadLocal<Choreographer> sThreadInstance =
@@ -74,6 +86,10 @@
 
     private static final int MSG_DO_ANIMATION = 0;
     private static final int MSG_DO_DRAW = 1;
+    private static final int MSG_DO_SCHEDULE_VSYNC = 2;
+    private static final int MSG_DO_DISPOSE_RECEIVER = 3;
+
+    private final Object mLock = new Object();
 
     private final Looper mLooper;
 
@@ -82,6 +98,7 @@
 
     private boolean mAnimationScheduled;
     private boolean mDrawScheduled;
+    private boolean mFrameDisplayEventReceiverNeeded;
     private FrameDisplayEventReceiver mFrameDisplayEventReceiver;
     private long mLastAnimationTime;
     private long mLastDrawTime;
@@ -94,8 +111,8 @@
     }
 
     /**
-     * Gets the choreographer for this thread.
-     * Must be called on the UI thread.
+     * Gets the choreographer for the calling thread.  Must be called from
+     * a thread that already has a {@link android.os.Looper} associated with it.
      *
      * @return The choreographer for this thread.
      * @throws IllegalStateException if the thread does not have a looper.
@@ -138,19 +155,35 @@
 
     /**
      * Schedules animation (and drawing) to occur on the next frame synchronization boundary.
-     * Must be called on the UI thread.
      */
     public void scheduleAnimation() {
+        synchronized (mLock) {
+            scheduleAnimationLocked();
+        }
+    }
+
+    private void scheduleAnimationLocked() {
         if (!mAnimationScheduled) {
             mAnimationScheduled = true;
             if (USE_VSYNC) {
                 if (DEBUG) {
                     Log.d(TAG, "Scheduling vsync for animation.");
                 }
-                if (mFrameDisplayEventReceiver == null) {
-                    mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper);
+
+                // If running on the Looper thread, then schedule the vsync immediately,
+                // otherwise post a message to schedule the vsync from the UI thread
+                // as soon as possible.
+                if (!mFrameDisplayEventReceiverNeeded) {
+                    mFrameDisplayEventReceiverNeeded = true;
+                    if (mFrameDisplayEventReceiver != null) {
+                        removeMessages(MSG_DO_DISPOSE_RECEIVER);
+                    }
                 }
-                mFrameDisplayEventReceiver.scheduleVsync();
+                if (isRunningOnLooperThreadLocked()) {
+                    doScheduleVsyncLocked();
+                } else {
+                    sendMessageAtFrontOfQueue(obtainMessage(MSG_DO_SCHEDULE_VSYNC));
+                }
             } else {
                 final long now = SystemClock.uptimeMillis();
                 final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now);
@@ -163,23 +196,47 @@
     }
 
     /**
+     * Returns true if {@link #scheduleAnimation()} has been called but
+     * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has
+     * not yet been called.
+     */
+    public boolean isAnimationScheduled() {
+        synchronized (mLock) {
+            return mAnimationScheduled;
+        }
+    }
+
+    /**
      * Schedules drawing to occur on the next frame synchronization boundary.
      * Must be called on the UI thread.
      */
     public void scheduleDraw() {
-        if (!mDrawScheduled) {
-            mDrawScheduled = true;
-            if (USE_ANIMATION_TIMER_FOR_DRAW) {
-                scheduleAnimation();
-            } else {
-                if (DEBUG) {
-                    Log.d(TAG, "Scheduling draw immediately.");
+        synchronized (mLock) {
+            if (!mDrawScheduled) {
+                mDrawScheduled = true;
+                if (USE_ANIMATION_TIMER_FOR_DRAW) {
+                    scheduleAnimationLocked();
+                } else {
+                    if (DEBUG) {
+                        Log.d(TAG, "Scheduling draw immediately.");
+                    }
+                    sendEmptyMessage(MSG_DO_DRAW);
                 }
-                sendEmptyMessage(MSG_DO_DRAW);
             }
         }
     }
 
+    /**
+     * Returns true if {@link #scheduleDraw()} has been called but
+     * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has
+     * not yet been called.
+     */
+    public boolean isDrawScheduled() {
+        synchronized (mLock) {
+            return mDrawScheduled;
+        }
+    }
+
     @Override
     public void handleMessage(Message msg) {
         switch (msg.what) {
@@ -189,64 +246,109 @@
             case MSG_DO_DRAW:
                 doDraw();
                 break;
+            case MSG_DO_SCHEDULE_VSYNC:
+                doScheduleVsync();
+                break;
+            case MSG_DO_DISPOSE_RECEIVER:
+                doDisposeReceiver();
+                break;
         }
     }
 
     private void doAnimation() {
-        if (mAnimationScheduled) {
-            mAnimationScheduled = false;
-
-            final long start = SystemClock.uptimeMillis();
-            if (DEBUG) {
-                Log.d(TAG, "Performing animation: " + Math.max(0, start - mLastAnimationTime)
-                        + " ms have elapsed since previous animation.");
-            }
-            mLastAnimationTime = start;
-
-            final OnAnimateListener[] listeners = mOnAnimateListeners;
-            if (listeners != null) {
-                for (int i = 0; i < listeners.length; i++) {
-                    listeners[i].onAnimate();
-                }
-            }
-
-            if (DEBUG) {
-                Log.d(TAG, "Animation took " + (SystemClock.uptimeMillis() - start) + " ms.");
-            }
-        }
+        doAnimationInner();
 
         if (USE_ANIMATION_TIMER_FOR_DRAW) {
             doDraw();
         }
     }
 
+    private void doAnimationInner() {
+        final long start;
+        final OnAnimateListener[] listeners;
+        synchronized (mLock) {
+            if (!mAnimationScheduled) {
+                return; // no work to do
+            }
+            mAnimationScheduled = false;
+
+            start = SystemClock.uptimeMillis();
+            if (DEBUG) {
+                Log.d(TAG, "Performing animation: " + Math.max(0, start - mLastAnimationTime)
+                        + " ms have elapsed since previous animation.");
+            }
+            mLastAnimationTime = start;
+
+            listeners = mOnAnimateListeners;
+        }
+
+        if (listeners != null) {
+            for (int i = 0; i < listeners.length; i++) {
+                listeners[i].onAnimate();
+            }
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "Animation took " + (SystemClock.uptimeMillis() - start) + " ms.");
+        }
+    }
+
     private void doDraw() {
-        if (mDrawScheduled) {
+        final long start;
+        final OnDrawListener[] listeners;
+        synchronized (mLock) {
+            if (!mDrawScheduled) {
+                return; // no work to do
+            }
             mDrawScheduled = false;
 
-            final long start = SystemClock.uptimeMillis();
+            start = SystemClock.uptimeMillis();
             if (DEBUG) {
                 Log.d(TAG, "Performing draw: " + Math.max(0, start - mLastDrawTime)
                         + " ms have elapsed since previous draw.");
             }
             mLastDrawTime = start;
 
-            final OnDrawListener[] listeners = mOnDrawListeners;
-            if (listeners != null) {
-                for (int i = 0; i < listeners.length; i++) {
-                    listeners[i].onDraw();
-                }
-            }
+            listeners = mOnDrawListeners;
+        }
 
-            if (DEBUG) {
-                Log.d(TAG, "Draw took " + (SystemClock.uptimeMillis() - start) + " ms.");
+        if (listeners != null) {
+            for (int i = 0; i < listeners.length; i++) {
+                listeners[i].onDraw();
+            }
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "Draw took " + (SystemClock.uptimeMillis() - start) + " ms.");
+        }
+    }
+
+    private void doScheduleVsync() {
+        synchronized (mLock) {
+            doScheduleVsyncLocked();
+        }
+    }
+
+    private void doScheduleVsyncLocked() {
+        if (mFrameDisplayEventReceiverNeeded && mAnimationScheduled) {
+            if (mFrameDisplayEventReceiver == null) {
+                mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper);
+            }
+            mFrameDisplayEventReceiver.scheduleVsync();
+        }
+    }
+
+    private void doDisposeReceiver() {
+        synchronized (mLock) {
+            if (!mFrameDisplayEventReceiverNeeded && mFrameDisplayEventReceiver != null) {
+                mFrameDisplayEventReceiver.dispose();
+                mFrameDisplayEventReceiver = null;
             }
         }
     }
 
     /**
      * Adds an animation listener.
-     * Must be called on the UI thread.
      *
      * @param listener The listener to add.
      */
@@ -259,13 +361,14 @@
             Log.d(TAG, "Adding onAnimate listener: " + listener);
         }
 
-        mOnAnimateListeners = ArrayUtils.appendElement(OnAnimateListener.class,
-                mOnAnimateListeners, listener);
+        synchronized (mLock) {
+            mOnAnimateListeners = ArrayUtils.appendElement(OnAnimateListener.class,
+                    mOnAnimateListeners, listener);
+        }
     }
 
     /**
      * Removes an animation listener.
-     * Must be called on the UI thread.
      *
      * @param listener The listener to remove.
      */
@@ -278,14 +381,15 @@
             Log.d(TAG, "Removing onAnimate listener: " + listener);
         }
 
-        mOnAnimateListeners = ArrayUtils.removeElement(OnAnimateListener.class,
-                mOnAnimateListeners, listener);
-        stopTimingLoopIfNoListeners();
+        synchronized (mLock) {
+            mOnAnimateListeners = ArrayUtils.removeElement(OnAnimateListener.class,
+                    mOnAnimateListeners, listener);
+            stopTimingLoopIfNoListenersLocked();
+        }
     }
 
     /**
      * Adds a draw listener.
-     * Must be called on the UI thread.
      *
      * @param listener The listener to add.
      */
@@ -298,8 +402,10 @@
             Log.d(TAG, "Adding onDraw listener: " + listener);
         }
 
-        mOnDrawListeners = ArrayUtils.appendElement(OnDrawListener.class,
-                mOnDrawListeners, listener);
+        synchronized (mLock) {
+            mOnDrawListeners = ArrayUtils.appendElement(OnDrawListener.class,
+                    mOnDrawListeners, listener);
+        }
     }
 
     /**
@@ -317,12 +423,14 @@
             Log.d(TAG, "Removing onDraw listener: " + listener);
         }
 
-        mOnDrawListeners = ArrayUtils.removeElement(OnDrawListener.class,
-                mOnDrawListeners, listener);
-        stopTimingLoopIfNoListeners();
+        synchronized (mLock) {
+            mOnDrawListeners = ArrayUtils.removeElement(OnDrawListener.class,
+                    mOnDrawListeners, listener);
+            stopTimingLoopIfNoListenersLocked();
+        }
     }
 
-    private void stopTimingLoopIfNoListeners() {
+    private void stopTimingLoopIfNoListenersLocked() {
         if (mOnDrawListeners == null && mOnAnimateListeners == null) {
             if (DEBUG) {
                 Log.d(TAG, "Stopping timing loop.");
@@ -330,7 +438,9 @@
 
             if (mAnimationScheduled) {
                 mAnimationScheduled = false;
-                if (!USE_VSYNC) {
+                if (USE_VSYNC) {
+                    removeMessages(MSG_DO_SCHEDULE_VSYNC);
+                } else {
                     removeMessages(MSG_DO_ANIMATION);
                 }
             }
@@ -342,13 +452,24 @@
                 }
             }
 
-            if (mFrameDisplayEventReceiver != null) {
-                mFrameDisplayEventReceiver.dispose();
-                mFrameDisplayEventReceiver = null;
+            // Post a message to dispose the display event receiver if we haven't needed
+            // it again after a certain amount of time has elapsed.  Another reason to
+            // defer disposal is that it is possible for use to attempt to dispose the
+            // receiver while handling a vsync event that it dispatched, which might
+            // cause a few problems...
+            if (mFrameDisplayEventReceiverNeeded) {
+                mFrameDisplayEventReceiverNeeded = false;
+                if (mFrameDisplayEventReceiver != null) {
+                    sendEmptyMessageDelayed(MSG_DO_DISPOSE_RECEIVER, DISPOSE_RECEIVER_DELAY);
+                }
             }
         }
     }
 
+    private boolean isRunningOnLooperThreadLocked() {
+        return Looper.myLooper() == mLooper;
+    }
+
     /**
      * Listens for animation frame timing events.
      */
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index d6711ee..6c2e540 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -25,6 +25,10 @@
 /**
  * Provides a low-level mechanism for an application to receive display events
  * such as vertical sync.
+ *
+ * The display event receive is NOT thread safe.  Moreover, its methods must only
+ * be called on the Looper thread to which it is attached.
+ *
  * @hide
  */
 public abstract class DisplayEventReceiver {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index c08a4024..1e92b43 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -189,7 +189,7 @@
     }
 
     private static native int nGetMaximumTextureWidth();
-    private static native int nGetMaximumTextureHeight();    
+    private static native int nGetMaximumTextureHeight();
 
     ///////////////////////////////////////////////////////////////////////////
     // Setup
@@ -268,6 +268,24 @@
 
     private static native void nFinish(int renderer);
 
+    /**
+     * Returns the size of the stencil buffer required by the underlying
+     * implementation.
+     * 
+     * @return The minimum number of bits the stencil buffer must. Always >= 0.
+     * 
+     * @hide
+     */
+    public static int getStencilSize() {
+        return nGetStencilSize();
+    }
+
+    private static native int nGetStencilSize();
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Functor
+    ///////////////////////////////////////////////////////////////////////////
+
     @Override
     public boolean callDrawGLFunction(int drawGLFunction) {
         return nCallDrawGLFunction(mRenderer, drawGLFunction);
@@ -275,7 +293,6 @@
 
     private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
 
-
     ///////////////////////////////////////////////////////////////////////////
     // Memory
     ///////////////////////////////////////////////////////////////////////////
@@ -361,6 +378,12 @@
 
     private static native int nGetDisplayListSize(int displayList);
 
+    static void setDisplayListName(int displayList, String name) {
+        nSetDisplayListName(displayList, name);
+    }
+
+    private static native void nSetDisplayListName(int displayList, String name);
+
     @Override
     public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
         return nDrawDisplayList(mRenderer,
@@ -700,6 +723,7 @@
 
     @Override
     public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
+        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing patches
         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -713,6 +737,7 @@
 
     @Override
     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
+        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -725,6 +750,7 @@
 
     @Override
     public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
+        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -738,6 +764,7 @@
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
+        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -761,6 +788,7 @@
 
     @Override
     public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
+        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
@@ -809,6 +837,7 @@
     @Override
     public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
             int vertOffset, int[] colors, int colorOffset, Paint paint) {
+        if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         if (meshWidth < 0 || meshHeight < 0 || vertOffset < 0 || colorOffset < 0) {
             throw new ArrayIndexOutOfBoundsException();
         }
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 0cb9449..969c9ab 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -31,10 +31,17 @@
     private GLES20RecordingCanvas mCanvas;
     private boolean mValid;
 
+    // Used for debugging
+    private final String mName;
+
     // The native display list will be destroyed when this object dies.
     // DO NOT overwrite this reference once it is set.
     private DisplayListFinalizer mFinalizer;
 
+    GLES20DisplayList(String name) {
+        mName = name;
+    }
+
     int getNativeDisplayList() {
         if (!mValid || mFinalizer == null) {
             throw new IllegalStateException("The display list is not valid.");
@@ -75,6 +82,7 @@
                 mCanvas.end(mFinalizer.mNativeDisplayList);
             } else {
                 mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
+                GLES20Canvas.setDisplayListName(mFinalizer.mNativeDisplayList, mName);
             }
             mCanvas.recycle();
             mCanvas = null;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 4592ae6..1932c7f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -39,6 +39,7 @@
 import javax.microedition.khronos.opengles.GL;
 
 import java.io.File;
+import java.io.PrintWriter;
 
 import static javax.microedition.khronos.egl.EGL10.*;
 
@@ -84,13 +85,27 @@
     static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync";
 
     /**
+     * System property used to enable or disable hardware rendering profiling.
+     * The default value of this property is assumed to be false.
+     * 
+     * When profiling is enabled, the adb shell dumpsys gfxinfo command will
+     * output extra information about the time taken to execute by the last
+     * frames.
+     *
+     * Possible values:
+     * "true", to enable profiling
+     * "false", to disable profiling
+     */
+    static final String PROFILE_PROPERTY = "hwui.profile";
+
+    /**
      * System property used to debug EGL configuration choice.
      * 
      * Possible values:
      * "choice", print the chosen configuration only
      * "all", print all possible configurations
      */
-    static final String PRINT_CONFIG_PROPERTY = "hwui.print_config";    
+    static final String PRINT_CONFIG_PROPERTY = "hwui.print_config";
 
     /**
      * Turn on to draw dirty regions every other frame.
@@ -112,6 +127,16 @@
      */
     public static boolean sSystemRendererDisabled = false;
 
+    /**
+     * Number of frames to profile.
+     */
+    private static final int PROFILE_MAX_FRAMES = 64;
+
+    /**
+     * Number of floats per profiled frame.
+     */
+    private static final int PROFILE_FRAME_DATA_COUNT = 3;
+
     private boolean mEnabled;
     private boolean mRequested = true;
 
@@ -226,6 +251,12 @@
     abstract HardwareCanvas getCanvas();
 
     /**
+     * Outputs extra debugging information in the specified file descriptor.
+     * @param pw
+     */
+    abstract void dumpGfxInfo(PrintWriter pw);
+    
+    /**
      * Sets the directory to use as a persistent storage for hardware rendering
      * resources.
      * 
@@ -238,6 +269,15 @@
     private static native void nSetupShadersDiskCache(String cacheFile);
 
     /**
+     * Notifies EGL that the frame is about to be rendered.
+     */
+    private static void beginFrame() {
+        nBeginFrame();
+    }
+
+    private static native void nBeginFrame();
+
+    /**
      * Interface used to receive callbacks whenever a view is drawn by
      * a hardware renderer instance.
      */
@@ -274,9 +314,12 @@
      * Creates a new display list that can be used to record batches of
      * drawing operations.
      * 
+     * @param name The name of the display list, used for debugging purpose.
+     *             May be null
+     * 
      * @return A new display list.
      */
-    public abstract DisplayList createDisplayList();
+    public abstract DisplayList createDisplayList(String name);
 
     /**
      * Creates a new hardware layer. A hardware layer built by calling this
@@ -427,6 +470,7 @@
         
         GL mGl;
         HardwareCanvas mCanvas;
+
         int mFrameCount;
         Paint mDebugPaint;
 
@@ -444,6 +488,10 @@
 
         final boolean mVsyncDisabled;
 
+        final boolean mProfileEnabled;
+        final float[] mProfileData;
+        int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
+
         final int mGlVersion;
         final boolean mTranslucent;
 
@@ -460,6 +508,34 @@
             if (mVsyncDisabled) {
                 Log.d(LOG_TAG, "Disabling v-sync");
             }
+
+            //noinspection PointlessBooleanExpression,ConstantConditions
+            if (!ViewDebug.DEBUG_LATENCY) {
+                final String profileProperty = SystemProperties.get(PROFILE_PROPERTY, "false");
+                mProfileEnabled = "true".equalsIgnoreCase(profileProperty);
+                if (mProfileEnabled) {
+                    Log.d(LOG_TAG, "Profiling hardware renderer");
+                }
+            } else {
+                mProfileEnabled = true;
+            }
+
+            if (mProfileEnabled) {
+                mProfileData = new float[PROFILE_MAX_FRAMES * PROFILE_FRAME_DATA_COUNT];
+            } else {
+                mProfileData = null;
+            }
+        }
+
+        @Override
+        void dumpGfxInfo(PrintWriter pw) {
+            if (mProfileEnabled) {
+                pw.printf("\n\tDraw\tProcess\tExecute\n");
+                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+                    pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
+                            mProfileData[i + 2]);
+                }
+            }
         }
 
         /**
@@ -808,6 +884,7 @@
         }        
         
         void onPreDraw(Rect dirty) {
+            
         }
 
         void onPostDraw() {
@@ -832,6 +909,8 @@
                         dirty = null;
                     }
 
+                    beginFrame();
+
                     onPreDraw(dirty);
 
                     HardwareCanvas canvas = mCanvas;
@@ -845,34 +924,49 @@
                                 (view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED;
                         view.mPrivateFlags &= ~View.INVALIDATED;
 
-                        final long getDisplayListStartTime;
-                        if (ViewDebug.DEBUG_LATENCY) {
+                        long getDisplayListStartTime = 0;
+                        if (mProfileEnabled) {
+                            mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
+                            if (mProfileCurrentFrame >= mProfileData.length) {
+                                mProfileCurrentFrame = 0;
+                            }
+
                             getDisplayListStartTime = System.nanoTime();
                         }
 
                         DisplayList displayList = view.getDisplayList();
 
-                        if (ViewDebug.DEBUG_LATENCY) {
+                        if (mProfileEnabled) {
                             long now = System.nanoTime();
-                            Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took "
-                                    + ((now - getDisplayListStartTime) * 0.000001f) + "ms");
+                            float total = (now - getDisplayListStartTime) * 0.000001f;
+                            //noinspection PointlessArithmeticExpression
+                            mProfileData[mProfileCurrentFrame] = total;
+
+                            if (ViewDebug.DEBUG_LATENCY) {
+                                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took " +
+                                        total + "ms");
+                            }
                         }
 
                         if (displayList != null) {
-                            final long drawDisplayListStartTime;
-                            if (ViewDebug.DEBUG_LATENCY) {
+                            long drawDisplayListStartTime = 0;
+                            if (mProfileEnabled) {
                                 drawDisplayListStartTime = System.nanoTime();
                             }
 
-                            boolean invalidateNeeded = canvas.drawDisplayList(
-                                    displayList, view.getWidth(),
-                                    view.getHeight(), mRedrawClip);
+                            boolean invalidateNeeded = canvas.drawDisplayList(displayList,
+                                    view.getWidth(), view.getHeight(), mRedrawClip);
 
-                            if (ViewDebug.DEBUG_LATENCY) {
+                            if (mProfileEnabled) {
                                 long now = System.nanoTime();
-                                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took "
-                                        + ((now - drawDisplayListStartTime) * 0.000001f)
-                                        + "ms, invalidateNeeded=" + invalidateNeeded + ".");
+                                float total = (now - drawDisplayListStartTime) * 0.000001f;
+                                mProfileData[mProfileCurrentFrame + 1] = total;
+
+                                if (ViewDebug.DEBUG_LATENCY) {
+                                    Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took " +
+                                            total + "ms, invalidateNeeded=" +
+                                            invalidateNeeded + ".");
+                                }
                             }
 
                             if (invalidateNeeded) {
@@ -907,17 +1001,22 @@
 
                     attachInfo.mIgnoreDirtyState = false;
 
-                    final long eglSwapBuffersStartTime;
-                    if (ViewDebug.DEBUG_LATENCY) {
+                    long eglSwapBuffersStartTime = 0;
+                    if (mProfileEnabled) {
                         eglSwapBuffersStartTime = System.nanoTime();
                     }
 
                     sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
 
-                    if (ViewDebug.DEBUG_LATENCY) {
+                    if (mProfileEnabled) {
                         long now = System.nanoTime();
-                        Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- eglSwapBuffers() took "
-                                + ((now - eglSwapBuffersStartTime) * 0.000001f) + "ms");
+                        float total = (now - eglSwapBuffersStartTime) * 0.000001f;
+                        mProfileData[mProfileCurrentFrame + 2] = total;
+
+                        if (ViewDebug.DEBUG_LATENCY) {
+                            Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- eglSwapBuffers() took " +
+                                    total + "ms");
+                        }
                     }
 
                     checkEglErrors();
@@ -1035,7 +1134,7 @@
                     EGL_BLUE_SIZE, 8,
                     EGL_ALPHA_SIZE, 8,
                     EGL_DEPTH_SIZE, 0,
-                    EGL_STENCIL_SIZE, 0,
+                    EGL_STENCIL_SIZE, GLES20Canvas.getStencilSize(),
                     EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
                             (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
                     EGL_NONE
@@ -1082,8 +1181,8 @@
         }
 
         @Override
-        public DisplayList createDisplayList() {
-            return new GLES20DisplayList();
+        public DisplayList createDisplayList(String name) {
+            return new GLES20DisplayList(name);
         }
 
         @Override
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 764d8dc..6a457ec 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -21,6 +21,7 @@
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.util.Log;
+import android.util.SparseIntArray;
 
 /**
  * Provides a low-level mechanism for an application to receive input events.
@@ -38,13 +39,14 @@
     private InputChannel mInputChannel;
     private MessageQueue mMessageQueue;
 
-    // The sequence number of the event that is in progress.
-    private int mEventSequenceNumberInProgress = -1;
+    // Map from InputEvent sequence numbers to dispatcher sequence numbers.
+    private final SparseIntArray mSeqMap = new SparseIntArray();
 
     private static native int nativeInit(InputEventReceiver receiver,
             InputChannel inputChannel, MessageQueue messageQueue);
     private static native void nativeDispose(int receiverPtr);
-    private static native void nativeFinishInputEvent(int receiverPtr, boolean handled);
+    private static native void nativeFinishInputEvent(int receiverPtr, int seq, boolean handled);
+    private static native void nativeConsumeBatchedInputEvents(int receiverPtr);
 
     /**
      * Creates an input event receiver bound to the specified input channel.
@@ -104,12 +106,25 @@
     }
 
     /**
+     * Called when a batched input event is pending.
+     *
+     * The batched input event will continue to accumulate additional movement
+     * samples until the recipient calls {@link #consumeBatchedInputEvents} or
+     * an event is received that ends the batch and causes it to be consumed
+     * immediately (such as a pointer up event).
+     */
+    public void onBatchedInputEventPending() {
+        consumeBatchedInputEvents();
+    }
+
+    /**
      * Finishes an input event and indicates whether it was handled.
+     * Must be called on the same Looper thread to which the receiver is attached.
      *
      * @param event The input event that was finished.
      * @param handled True if the event was handled.
      */
-    public void finishInputEvent(InputEvent event, boolean handled) {
+    public final void finishInputEvent(InputEvent event, boolean handled) {
         if (event == null) {
             throw new IllegalArgumentException("event must not be null");
         }
@@ -117,23 +132,47 @@
             Log.w(TAG, "Attempted to finish an input event but the input event "
                     + "receiver has already been disposed.");
         } else {
-            if (event.getSequenceNumber() != mEventSequenceNumberInProgress) {
+            int index = mSeqMap.indexOfKey(event.getSequenceNumber());
+            if (index < 0) {
                 Log.w(TAG, "Attempted to finish an input event that is not in progress.");
             } else {
-                mEventSequenceNumberInProgress = -1;
-                nativeFinishInputEvent(mReceiverPtr, handled);
+                int seq = mSeqMap.valueAt(index);
+                mSeqMap.removeAt(index);
+                nativeFinishInputEvent(mReceiverPtr, seq, handled);
             }
         }
         event.recycleIfNeededAfterDispatch();
     }
 
+    /**
+     * Consumes all pending batched input events.
+     * Must be called on the same Looper thread to which the receiver is attached.
+     *
+     * This method forces all batched input events to be delivered immediately.
+     * Should be called just before animating or drawing a new frame in the UI.
+     */
+    public final void consumeBatchedInputEvents() {
+        if (mReceiverPtr == 0) {
+            Log.w(TAG, "Attempted to consume batched input events but the input event "
+                    + "receiver has already been disposed.");
+        } else {
+            nativeConsumeBatchedInputEvents(mReceiverPtr);
+        }
+    }
+
     // Called from native code.
     @SuppressWarnings("unused")
-    private void dispatchInputEvent(InputEvent event) {
-        mEventSequenceNumberInProgress = event.getSequenceNumber();
+    private void dispatchInputEvent(int seq, InputEvent event) {
+        mSeqMap.put(event.getSequenceNumber(), seq);
         onInputEvent(event);
     }
 
+    // Called from native code.
+    @SuppressWarnings("unused")
+    private void dispatchBatchedInputEventPending() {
+        onBatchedInputEventPending();
+    }
+
     public static interface Factory {
         public InputEventReceiver createInputEventReceiver(
                 InputChannel inputChannel, Looper looper);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8cac57d..87104f4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -65,6 +65,7 @@
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
+import android.view.animation.Transformation;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
@@ -2166,15 +2167,13 @@
         float mScaleY = 1f;
 
         /**
-         * The amount of scale in the x direction around the pivot point. A
-         * value of 1 means no scaling is applied.
+         * The x location of the point around which the view is rotated and scaled.
          */
         @ViewDebug.ExportedProperty
         float mPivotX = 0f;
 
         /**
-         * The amount of scale in the y direction around the pivot point. A
-         * value of 1 means no scaling is applied.
+         * The y location of the point around which the view is rotated and scaled.
          */
         @ViewDebug.ExportedProperty
         float mPivotY = 0f;
@@ -2619,7 +2618,6 @@
 
     /**
      * Text direction is inherited thru {@link ViewGroup}
-     * @hide
      */
     public static final int TEXT_DIRECTION_INHERIT = 0;
 
@@ -2628,7 +2626,6 @@
      * determines the paragraph direction. If there is no strong directional character, the
      * paragraph direction is the view's resolved layout direction.
      *
-     * @hide
      */
     public static final int TEXT_DIRECTION_FIRST_STRONG = 1;
 
@@ -2637,42 +2634,36 @@
      * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters.
      * If there are neither, the paragraph direction is the view's resolved layout direction.
      *
-     * @hide
      */
     public static final int TEXT_DIRECTION_ANY_RTL = 2;
 
     /**
      * Text direction is forced to LTR.
      *
-     * @hide
      */
     public static final int TEXT_DIRECTION_LTR = 3;
 
     /**
      * Text direction is forced to RTL.
      *
-     * @hide
      */
     public static final int TEXT_DIRECTION_RTL = 4;
 
     /**
      * Text direction is coming from the system Locale.
      *
-     * @hide
      */
     public static final int TEXT_DIRECTION_LOCALE = 5;
 
     /**
      * Default text direction is inherited
      *
-     * @hide
      */
     protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT;
 
     /**
      * The text direction that has been defined by {@link #setTextDirection(int)}.
      *
-     * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "text", mapping = {
             @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
@@ -2690,7 +2681,6 @@
      * not TEXT_DIRECTION_INHERIT, otherwise resolution proceeds up the parent
      * chain of the view.
      *
-     * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "text", mapping = {
             @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
@@ -3761,8 +3751,14 @@
     }
 
     /**
-     * Called when this view wants to give up focus. This will cause
-     * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called.
+     * Called when this view wants to give up focus. If focus is cleared
+     * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called.
+     * <p>
+     * <strong>Note:</strong> When a View clears focus the framework is trying
+     * to give focus to the first focusable View from the top. Hence, if this
+     * View is the first from the top that can take focus, then its focus will
+     * not be cleared nor will the focus change callback be invoked.
+     * </p>
      */
     public void clearFocus() {
         if (DBG) {
@@ -6822,7 +6818,8 @@
 
         if ((changed & VISIBILITY_MASK) != 0) {
             if (mParent instanceof ViewGroup) {
-                ((ViewGroup) mParent).onChildVisibilityChanged(this, (flags & VISIBILITY_MASK));
+                ((ViewGroup) mParent).onChildVisibilityChanged(this, (changed & VISIBILITY_MASK),
+                        (flags & VISIBILITY_MASK));
                 ((View) mParent).invalidate(true);
             } else if (mParent != null) {
                 mParent.invalidateChild(this, null);
@@ -7282,6 +7279,7 @@
      * 
      * @return The degrees of rotation.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getRotation() {
         return mTransformationInfo != null ? mTransformationInfo.mRotation : 0;
     }
@@ -7323,6 +7321,7 @@
      * 
      * @return The degrees of Y rotation.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getRotationY() {
         return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0;
     }
@@ -7369,6 +7368,7 @@
      * 
      * @return The degrees of X rotation.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getRotationX() {
         return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0;
     }
@@ -7416,6 +7416,7 @@
      * @see #getPivotY()
      * @return The scaling factor.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getScaleX() {
         return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1;
     }
@@ -7454,6 +7455,7 @@
      * @see #getPivotY()
      * @return The scaling factor.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getScaleY() {
         return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1;
     }
@@ -7492,6 +7494,7 @@
      * @see #getPivotY()
      * @return The x location of the pivot point.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getPivotX() {
         return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0;
     }
@@ -7536,6 +7539,7 @@
      * @see #getPivotY()
      * @return The y location of the pivot point.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getPivotY() {
         return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0;
     }
@@ -7576,6 +7580,7 @@
      * <p>By default this is 1.0f.
      * @return The opacity of the view.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getAlpha() {
         return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
     }
@@ -7589,6 +7594,10 @@
      * equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and
      * setting a hardware layer.</p>
      *
+     * <p>Note that setting alpha to a translucent value (0 < alpha < 1) may have
+     * performance implications. It is generally best to use the alpha property sparingly and
+     * transiently, as in the case of fading animations.</p>
+     *
      * @param alpha The opacity of the view.
      *
      * @see #setLayerType(int, android.graphics.Paint)
@@ -7886,6 +7895,7 @@
      *
      * @return The visual x position of this view, in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getX() {
         return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0);
     }
@@ -7908,6 +7918,7 @@
      *
      * @return The visual y position of this view, in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getY() {
         return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0);
     }
@@ -7931,6 +7942,7 @@
      *
      * @return The horizontal position of this view relative to its left position, in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getTranslationX() {
         return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0;
     }
@@ -7967,6 +7979,7 @@
      * @return The vertical position of this view relative to its top position,
      * in pixels.
      */
+    @ViewDebug.ExportedProperty(category = "drawing")
     public float getTranslationY() {
         return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0;
     }
@@ -8208,6 +8221,9 @@
             throw new NullPointerException("Layout parameters cannot be null");
         }
         mLayoutParams = params;
+        if (mParent instanceof ViewGroup) {
+            ((ViewGroup) mParent).onSetLayoutParams(this, params);
+        }
         requestLayout();
     }
 
@@ -10373,7 +10389,8 @@
             // we copy in child display lists into ours in drawChild()
             mRecreateDisplayList = true;
             if (mDisplayList == null) {
-                mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList();
+                final String name = getClass().getSimpleName();
+                mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
                 // If we're creating a new display list, make sure our parent gets invalidated
                 // since they will need to recreate their display list to account for this
                 // new child display list.
@@ -10902,6 +10919,346 @@
     }
 
     /**
+     * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common
+     * case of an active Animation being run on the view.
+     */
+    private boolean drawAnimation(ViewGroup parent, long drawingTime,
+            Animation a, boolean scalingRequired) {
+        Transformation invalidationTransform;
+        final int flags = parent.mGroupFlags;
+        final boolean initialized = a.isInitialized();
+        if (!initialized) {
+            a.initialize(mRight - mLeft, mBottom - mTop, getWidth(), getHeight());
+            a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
+            onAnimationStart();
+        }
+
+        boolean more = a.getTransformation(drawingTime, parent.mChildTransformation, 1f);
+        if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
+            if (parent.mInvalidationTransformation == null) {
+                parent.mInvalidationTransformation = new Transformation();
+            }
+            invalidationTransform = parent.mInvalidationTransformation;
+            a.getTransformation(drawingTime, invalidationTransform, 1f);
+        } else {
+            invalidationTransform = parent.mChildTransformation;
+        }
+        if (more) {
+            if (!a.willChangeBounds()) {
+                if ((flags & (parent.FLAG_OPTIMIZE_INVALIDATE | parent.FLAG_ANIMATION_DONE)) ==
+                        parent.FLAG_OPTIMIZE_INVALIDATE) {
+                    parent.mGroupFlags |= parent.FLAG_INVALIDATE_REQUIRED;
+                } else if ((flags & parent.FLAG_INVALIDATE_REQUIRED) == 0) {
+                    // The child need to draw an animation, potentially offscreen, so
+                    // make sure we do not cancel invalidate requests
+                    parent.mPrivateFlags |= DRAW_ANIMATION;
+                    parent.invalidate(mLeft, mTop, mRight, mBottom);
+                }
+            } else {
+                if (parent.mInvalidateRegion == null) {
+                    parent.mInvalidateRegion = new RectF();
+                }
+                final RectF region = parent.mInvalidateRegion;
+                a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
+                        invalidationTransform);
+
+                // The child need to draw an animation, potentially offscreen, so
+                // make sure we do not cancel invalidate requests
+                parent.mPrivateFlags |= DRAW_ANIMATION;
+
+                final int left = mLeft + (int) region.left;
+                final int top = mTop + (int) region.top;
+                parent.invalidate(left, top, left + (int) (region.width() + .5f),
+                        top + (int) (region.height() + .5f));
+            }
+        }
+        return more;
+    }
+
+    /**
+     * This method is called by ViewGroup.drawChild() to have each child view draw itself.
+     * This draw() method is an implementation detail and is not intended to be overridden or
+     * to be called from anywhere else other than ViewGroup.drawChild().
+     */
+    boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
+        boolean more = false;
+        final boolean childHasIdentityMatrix = hasIdentityMatrix();
+        final int flags = parent.mGroupFlags;
+
+        if ((flags & parent.FLAG_CLEAR_TRANSFORMATION) == parent.FLAG_CLEAR_TRANSFORMATION) {
+            parent.mChildTransformation.clear();
+            parent.mGroupFlags &= ~parent.FLAG_CLEAR_TRANSFORMATION;
+        }
+
+        Transformation transformToApply = null;
+        boolean concatMatrix = false;
+
+        boolean scalingRequired = false;
+        boolean caching;
+        int layerType = parent.mDrawLayers ? getLayerType() : LAYER_TYPE_NONE;
+
+        final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
+        if ((flags & parent.FLAG_CHILDREN_DRAWN_WITH_CACHE) == parent.FLAG_CHILDREN_DRAWN_WITH_CACHE ||
+                (flags & parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) == parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) {
+            caching = true;
+            if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
+        } else {
+            caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
+        }
+
+        final Animation a = getAnimation();
+        if (a != null) {
+            more = drawAnimation(parent, drawingTime, a, scalingRequired);
+            concatMatrix = a.willChangeTransformationMatrix();
+            transformToApply = parent.mChildTransformation;
+        } else if ((flags & parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
+                parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
+            final boolean hasTransform =
+                    parent.getChildStaticTransformation(this, parent.mChildTransformation);
+            if (hasTransform) {
+                final int transformType = parent.mChildTransformation.getTransformationType();
+                transformToApply = transformType != Transformation.TYPE_IDENTITY ?
+                        parent.mChildTransformation : null;
+                concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
+            }
+        }
+
+        concatMatrix |= !childHasIdentityMatrix;
+
+        // Sets the flag as early as possible to allow draw() implementations
+        // to call invalidate() successfully when doing animations
+        mPrivateFlags |= DRAWN;
+
+        if (!concatMatrix && canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) &&
+                (mPrivateFlags & DRAW_ANIMATION) == 0) {
+            return more;
+        }
+
+        if (hardwareAccelerated) {
+            // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
+            // retain the flag's value temporarily in the mRecreateDisplayList flag
+            mRecreateDisplayList = (mPrivateFlags & INVALIDATED) == INVALIDATED;
+            mPrivateFlags &= ~INVALIDATED;
+        }
+
+        computeScroll();
+
+        final int sx = mScrollX;
+        final int sy = mScrollY;
+
+        DisplayList displayList = null;
+        Bitmap cache = null;
+        boolean hasDisplayList = false;
+        if (caching) {
+            if (!hardwareAccelerated) {
+                if (layerType != LAYER_TYPE_NONE) {
+                    layerType = LAYER_TYPE_SOFTWARE;
+                    buildDrawingCache(true);
+                }
+                cache = getDrawingCache(true);
+            } else {
+                switch (layerType) {
+                    case LAYER_TYPE_SOFTWARE:
+                        buildDrawingCache(true);
+                        cache = getDrawingCache(true);
+                        break;
+                    case LAYER_TYPE_NONE:
+                        // Delay getting the display list until animation-driven alpha values are
+                        // set up and possibly passed on to the view
+                        hasDisplayList = canHaveDisplayList();
+                        break;
+                }
+            }
+        }
+
+        final boolean hasNoCache = cache == null || hasDisplayList;
+        final boolean offsetForScroll = cache == null && !hasDisplayList &&
+                layerType != LAYER_TYPE_HARDWARE;
+
+        final int restoreTo = canvas.save();
+        if (offsetForScroll) {
+            canvas.translate(mLeft - sx, mTop - sy);
+        } else {
+            canvas.translate(mLeft, mTop);
+            if (scalingRequired) {
+                // mAttachInfo cannot be null, otherwise scalingRequired == false
+                final float scale = 1.0f / mAttachInfo.mApplicationScale;
+                canvas.scale(scale, scale);
+            }
+        }
+
+        float alpha = getAlpha();
+        if (transformToApply != null || alpha < 1.0f || !hasIdentityMatrix()) {
+            if (transformToApply != null || !childHasIdentityMatrix) {
+                int transX = 0;
+                int transY = 0;
+
+                if (offsetForScroll) {
+                    transX = -sx;
+                    transY = -sy;
+                }
+
+                if (transformToApply != null) {
+                    if (concatMatrix) {
+                        // Undo the scroll translation, apply the transformation matrix,
+                        // then redo the scroll translate to get the correct result.
+                        canvas.translate(-transX, -transY);
+                        canvas.concat(transformToApply.getMatrix());
+                        canvas.translate(transX, transY);
+                        parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+                    }
+
+                    float transformAlpha = transformToApply.getAlpha();
+                    if (transformAlpha < 1.0f) {
+                        alpha *= transformToApply.getAlpha();
+                        parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+                    }
+                }
+
+                if (!childHasIdentityMatrix) {
+                    canvas.translate(-transX, -transY);
+                    canvas.concat(getMatrix());
+                    canvas.translate(transX, transY);
+                }
+            }
+
+            if (alpha < 1.0f) {
+                parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+                if (hasNoCache) {
+                    final int multipliedAlpha = (int) (255 * alpha);
+                    if (!onSetAlpha(multipliedAlpha)) {
+                        int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
+                        if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN ||
+                                layerType != LAYER_TYPE_NONE) {
+                            layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
+                        }
+                        if (layerType == LAYER_TYPE_NONE) {
+                            final int scrollX = hasDisplayList ? 0 : sx;
+                            final int scrollY = hasDisplayList ? 0 : sy;
+                            canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
+                                    scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
+                        }
+                    } else {
+                        // Alpha is handled by the child directly, clobber the layer's alpha
+                        mPrivateFlags |= ALPHA_SET;
+                    }
+                }
+            }
+        } else if ((mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
+            onSetAlpha(255);
+            mPrivateFlags &= ~ALPHA_SET;
+        }
+
+        if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN) {
+            if (offsetForScroll) {
+                canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop));
+            } else {
+                if (!scalingRequired || cache == null) {
+                    canvas.clipRect(0, 0, mRight - mLeft, mBottom - mTop);
+                } else {
+                    canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
+                }
+            }
+        }
+
+        if (hasDisplayList) {
+            displayList = getDisplayList();
+            if (!displayList.isValid()) {
+                // Uncommon, but possible. If a view is removed from the hierarchy during the call
+                // to getDisplayList(), the display list will be marked invalid and we should not
+                // try to use it again.
+                displayList = null;
+                hasDisplayList = false;
+            }
+        }
+
+        if (hasNoCache) {
+            boolean layerRendered = false;
+            if (layerType == LAYER_TYPE_HARDWARE) {
+                final HardwareLayer layer = getHardwareLayer();
+                if (layer != null && layer.isValid()) {
+                    mLayerPaint.setAlpha((int) (alpha * 255));
+                    ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint);
+                    layerRendered = true;
+                } else {
+                    final int scrollX = hasDisplayList ? 0 : sx;
+                    final int scrollY = hasDisplayList ? 0 : sy;
+                    canvas.saveLayer(scrollX, scrollY,
+                            scrollX + mRight - mLeft, scrollY + mBottom - mTop, mLayerPaint,
+                            Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+                }
+            }
+
+            if (!layerRendered) {
+                if (!hasDisplayList) {
+                    // Fast path for layouts with no backgrounds
+                    if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+                        if (ViewDebug.TRACE_HIERARCHY) {
+                            ViewDebug.trace(parent, ViewDebug.HierarchyTraceType.DRAW);
+                        }
+                        mPrivateFlags &= ~DIRTY_MASK;
+                        dispatchDraw(canvas);
+                    } else {
+                        draw(canvas);
+                    }
+                } else {
+                    mPrivateFlags &= ~DIRTY_MASK;
+                    ((HardwareCanvas) canvas).drawDisplayList(displayList,
+                            mRight - mLeft, mBottom - mTop, null);
+                }
+            }
+        } else if (cache != null) {
+            mPrivateFlags &= ~DIRTY_MASK;
+            Paint cachePaint;
+
+            if (layerType == LAYER_TYPE_NONE) {
+                cachePaint = parent.mCachePaint;
+                if (cachePaint == null) {
+                    cachePaint = new Paint();
+                    cachePaint.setDither(false);
+                    parent.mCachePaint = cachePaint;
+                }
+                if (alpha < 1.0f) {
+                    cachePaint.setAlpha((int) (alpha * 255));
+                    parent.mGroupFlags |= parent.FLAG_ALPHA_LOWER_THAN_ONE;
+                } else if  ((flags & parent.FLAG_ALPHA_LOWER_THAN_ONE) ==
+                        parent.FLAG_ALPHA_LOWER_THAN_ONE) {
+                    cachePaint.setAlpha(255);
+                    parent.mGroupFlags &= ~parent.FLAG_ALPHA_LOWER_THAN_ONE;
+                }
+            } else {
+                cachePaint = mLayerPaint;
+                cachePaint.setAlpha((int) (alpha * 255));
+            }
+            canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
+        }
+
+        canvas.restoreToCount(restoreTo);
+
+        if (a != null && !more) {
+            if (!hardwareAccelerated && !a.getFillAfter()) {
+                onSetAlpha(255);
+            }
+            parent.finishAnimatingView(this, a);
+        }
+
+        if (more && hardwareAccelerated) {
+            // invalidation is the trigger to recreate display lists, so if we're using
+            // display lists to render, force an invalidate to allow the animation to
+            // continue drawing another frame
+            parent.invalidate(true);
+            if (a.hasAlpha() && (mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
+                // alpha animations should cause the child to recreate its display list
+                invalidate(true);
+            }
+        }
+
+        mRecreateDisplayList = false;
+
+        return more;
+    }
+
+    /**
      * Manually render this view (and all of its children) to the given Canvas.
      * The view must have already done a full layout before this function is
      * called.  When implementing a view, implement
@@ -12654,6 +13011,11 @@
             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
         }
 
+        if (getAccessibilityNodeProvider() != null) {
+            throw new IllegalStateException("Views with AccessibilityNodeProvider"
+                    + " can't have children.");
+        }
+
         mPrivateFlags |= FORCE_LAYOUT;
         mPrivateFlags |= INVALIDATED;
 
@@ -12684,9 +13046,9 @@
      * </p>
      *
      * <p>
-     * The actual mesurement work of a view is performed in
+     * The actual measurement work of a view is performed in
      * {@link #onMeasure(int, int)}, called by this method. Therefore, only
-     * {@link #onMeasure(int, int)} can and must be overriden by subclasses.
+     * {@link #onMeasure(int, int)} can and must be overridden by subclasses.
      * </p>
      *
      *
@@ -13712,7 +14074,6 @@
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE},
      *
-     * @hide
      */
     public int getTextDirection() {
         return mTextDirection;
@@ -13730,7 +14091,6 @@
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE},
      *
-     * @hide
      */
     public void setTextDirection(int textDirection) {
         if (textDirection != mTextDirection) {
@@ -13751,7 +14111,6 @@
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE},
      *
-     * @hide
      */
     public int getResolvedTextDirection() {
         if (mResolvedTextDirection == TEXT_DIRECTION_INHERIT) {
@@ -13763,7 +14122,6 @@
     /**
      * Resolve the text direction.
      *
-     * @hide
      */
     protected void resolveTextDirection() {
         if (mTextDirection != TEXT_DIRECTION_INHERIT) {
@@ -13780,7 +14138,6 @@
     /**
      * Reset resolved text direction. Will be resolved during a call to getResolvedTextDirection().
      *
-     * @hide
      */
     protected void resetResolvedTextDirection() {
         mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 5c63366..bc147ac 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -103,18 +103,18 @@
      * A Transformation used when drawing children, to
      * apply on the child being drawn.
      */
-    private final Transformation mChildTransformation = new Transformation();
+    final Transformation mChildTransformation = new Transformation();
 
     /**
      * Used to track the current invalidation region.
      */
-    private RectF mInvalidateRegion;
+    RectF mInvalidateRegion;
 
     /**
      * A Transformation used to calculate a correct
      * invalidation area when the application is autoscaled.
      */
-    private Transformation mInvalidationTransformation;
+    Transformation mInvalidationTransformation;
 
     // View currently under an ongoing drag
     private View mCurrentDragView;
@@ -170,7 +170,7 @@
 
     // When set, ViewGroup invalidates only the child's rectangle
     // Set by default
-    private static final int FLAG_CLIP_CHILDREN = 0x1;
+    static final int FLAG_CLIP_CHILDREN = 0x1;
 
     // When set, ViewGroup excludes the padding area from the invalidate rectangle
     // Set by default
@@ -178,7 +178,7 @@
 
     // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
     // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
-    private static final int FLAG_INVALIDATE_REQUIRED  = 0x4;
+    static final int FLAG_INVALIDATE_REQUIRED  = 0x4;
 
     // When set, dispatchDraw() will run the layout animation and unset the flag
     private static final int FLAG_RUN_ANIMATION = 0x8;
@@ -186,7 +186,7 @@
     // When set, there is either no layout animation on the ViewGroup or the layout
     // animation is over
     // Set by default
-    private static final int FLAG_ANIMATION_DONE = 0x10;
+    static final int FLAG_ANIMATION_DONE = 0x10;
 
     // If set, this ViewGroup has padding; if unset there is no padding and we don't need
     // to clip it, even if FLAG_CLIP_TO_PADDING is set
@@ -200,10 +200,10 @@
     // layout animation; this avoid clobbering the hierarchy
     // Automatically set when the layout animation starts, depending on the animation's
     // characteristics
-    private static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
+    static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
 
     // When set, the next call to drawChild() will clear mChildTransformation's matrix
-    private static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
+    static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
 
     // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
     // the children's Bitmap caches if necessary
@@ -233,7 +233,7 @@
 
     // When the previous drawChild() invocation used an alpha value that was lower than
     // 1.0 and set it in mCachePaint
-    private static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
+    static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
 
     /**
      * When set, this ViewGroup's drawable states also include those
@@ -244,13 +244,13 @@
     /**
      * When set, this ViewGroup tries to always draw its children using their drawing cache.
      */
-    private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
+    static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
 
     /**
      * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
      * draw its children with their drawing cache.
      */
-    private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
+    static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
 
     /**
      * When set, this group will go through its list of children to notify them of
@@ -352,7 +352,7 @@
     private static final int ARRAY_CAPACITY_INCREMENT = 12;
 
     // Used to draw cached views
-    private Paint mCachePaint;
+    Paint mCachePaint;
 
     // Used to animate add/remove changes in layout
     private LayoutTransition mTransition;
@@ -368,7 +368,7 @@
 
     // Indicates whether this container will use its children layers to draw
     @ViewDebug.ExportedProperty(category = "drawing")
-    private boolean mDrawLayers = true;
+    boolean mDrawLayers = true;
 
     public ViewGroup(Context context) {
         super(context);
@@ -888,18 +888,20 @@
     }
 
     /**
+     * Called when a view's visibility has changed. Notify the parent to take any appropriate
+     * action.
+     *
+     * @param child The view whose visibility has changed
+     * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
+     * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
      * @hide
-     * @param child
-     * @param visibility
      */
-    protected void onChildVisibilityChanged(View child, int visibility) {
+    protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
         if (mTransition != null) {
-            if (visibility == VISIBLE) {
-                mTransition.showChild(this, child);
+            if (newVisibility == VISIBLE) {
+                mTransition.showChild(this, child, oldVisibility);
             } else {
-                mTransition.hideChild(this, child);
-            }
-            if (visibility != VISIBLE) {
+                mTransition.hideChild(this, child, newVisibility);
                 // Only track this on disappearing views - appearing views are already visible
                 // and don't need special handling during drawChild()
                 if (mVisibilityChangingChildren == null) {
@@ -914,7 +916,7 @@
 
         // in all cases, for drags
         if (mCurrentDrag != null) {
-            if (visibility == VISIBLE) {
+            if (newVisibility == VISIBLE) {
                 notifyChildOfDrag(child);
             }
         }
@@ -2615,337 +2617,11 @@
      *
      * @param canvas The canvas on which to draw the child
      * @param child Who to draw
-     * @param drawingTime The time at which draw is occuring
+     * @param drawingTime The time at which draw is occurring
      * @return True if an invalidate() was issued
      */
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
-        boolean more = false;
-
-        final int cl = child.mLeft;
-        final int ct = child.mTop;
-        final int cr = child.mRight;
-        final int cb = child.mBottom;
-
-        final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
-
-        final int flags = mGroupFlags;
-
-        if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
-            mChildTransformation.clear();
-            mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
-        }
-
-        Transformation transformToApply = null;
-        Transformation invalidationTransform;
-        final Animation a = child.getAnimation();
-        boolean concatMatrix = false;
-
-        boolean scalingRequired = false;
-        boolean caching;
-        int layerType = mDrawLayers ? child.getLayerType() : LAYER_TYPE_NONE;
-
-        final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
-        if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
-                (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
-            caching = true;
-            if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
-        } else {
-            caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
-        }
-
-        if (a != null) {
-            final boolean initialized = a.isInitialized();
-            if (!initialized) {
-                a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
-                a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);
-                child.onAnimationStart();
-            }
-
-            more = a.getTransformation(drawingTime, mChildTransformation,
-                    scalingRequired ? mAttachInfo.mApplicationScale : 1f);
-            if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
-                if (mInvalidationTransformation == null) {
-                    mInvalidationTransformation = new Transformation();
-                }
-                invalidationTransform = mInvalidationTransformation;
-                a.getTransformation(drawingTime, invalidationTransform, 1f);
-            } else {
-                invalidationTransform = mChildTransformation;
-            }
-            transformToApply = mChildTransformation;
-
-            concatMatrix = a.willChangeTransformationMatrix();
-
-            if (more) {
-                if (!a.willChangeBounds()) {
-                    if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) ==
-                            FLAG_OPTIMIZE_INVALIDATE) {
-                        mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
-                    } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
-                        // The child need to draw an animation, potentially offscreen, so
-                        // make sure we do not cancel invalidate requests
-                        mPrivateFlags |= DRAW_ANIMATION;
-                        invalidate(cl, ct, cr, cb);
-                    }
-                } else {
-                    if (mInvalidateRegion == null) {
-                        mInvalidateRegion = new RectF();
-                    }
-                    final RectF region = mInvalidateRegion;
-                    a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, invalidationTransform);
-
-                    // The child need to draw an animation, potentially offscreen, so
-                    // make sure we do not cancel invalidate requests
-                    mPrivateFlags |= DRAW_ANIMATION;
-
-                    final int left = cl + (int) region.left;
-                    final int top = ct + (int) region.top;
-                    invalidate(left, top, left + (int) (region.width() + .5f),
-                            top + (int) (region.height() + .5f));
-                }
-            }
-        } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
-                FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
-            final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
-            if (hasTransform) {
-                final int transformType = mChildTransformation.getTransformationType();
-                transformToApply = transformType != Transformation.TYPE_IDENTITY ?
-                        mChildTransformation : null;
-                concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
-            }
-        }
-
-        concatMatrix |= !childHasIdentityMatrix;
-
-        // Sets the flag as early as possible to allow draw() implementations
-        // to call invalidate() successfully when doing animations
-        child.mPrivateFlags |= DRAWN;
-
-        if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
-                (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
-            return more;
-        }
-
-        if (hardwareAccelerated) {
-            // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
-            // retain the flag's value temporarily in the mRecreateDisplayList flag
-            child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
-            child.mPrivateFlags &= ~INVALIDATED;
-        }
-
-        child.computeScroll();
-
-        final int sx = child.mScrollX;
-        final int sy = child.mScrollY;
-
-        DisplayList displayList = null;
-        Bitmap cache = null;
-        boolean hasDisplayList = false;
-        if (caching) {
-            if (!hardwareAccelerated) {
-                if (layerType != LAYER_TYPE_NONE) {
-                    layerType = LAYER_TYPE_SOFTWARE;
-                    child.buildDrawingCache(true);
-                }
-                cache = child.getDrawingCache(true);
-            } else {
-                switch (layerType) {
-                    case LAYER_TYPE_SOFTWARE:
-                        child.buildDrawingCache(true);
-                        cache = child.getDrawingCache(true);
-                        break;
-                    case LAYER_TYPE_NONE:
-                        // Delay getting the display list until animation-driven alpha values are
-                        // set up and possibly passed on to the view
-                        hasDisplayList = child.canHaveDisplayList();
-                        break;
-                }
-            }
-        }
-
-        final boolean hasNoCache = cache == null || hasDisplayList;
-        final boolean offsetForScroll = cache == null && !hasDisplayList &&
-                layerType != LAYER_TYPE_HARDWARE;
-
-        final int restoreTo = canvas.save();
-        if (offsetForScroll) {
-            canvas.translate(cl - sx, ct - sy);
-        } else {
-            canvas.translate(cl, ct);
-            if (scalingRequired) {
-                // mAttachInfo cannot be null, otherwise scalingRequired == false
-                final float scale = 1.0f / mAttachInfo.mApplicationScale;
-                canvas.scale(scale, scale);
-            }
-        }
-
-        float alpha = child.getAlpha();
-        if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
-            if (transformToApply != null || !childHasIdentityMatrix) {
-                int transX = 0;
-                int transY = 0;
-
-                if (offsetForScroll) {
-                    transX = -sx;
-                    transY = -sy;
-                }
-
-                if (transformToApply != null) {
-                    if (concatMatrix) {
-                        // Undo the scroll translation, apply the transformation matrix,
-                        // then redo the scroll translate to get the correct result.
-                        canvas.translate(-transX, -transY);
-                        canvas.concat(transformToApply.getMatrix());
-                        canvas.translate(transX, transY);
-                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
-                    }
-
-                    float transformAlpha = transformToApply.getAlpha();
-                    if (transformAlpha < 1.0f) {
-                        alpha *= transformToApply.getAlpha();
-                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
-                    }
-                }
-
-                if (!childHasIdentityMatrix) {
-                    canvas.translate(-transX, -transY);
-                    canvas.concat(child.getMatrix());
-                    canvas.translate(transX, transY);
-                }
-            }
-
-            if (alpha < 1.0f) {
-                mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
-                if (hasNoCache) {
-                    final int multipliedAlpha = (int) (255 * alpha);
-                    if (!child.onSetAlpha(multipliedAlpha)) {
-                        int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
-                        if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN ||
-                                layerType != LAYER_TYPE_NONE) {
-                            layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
-                        }
-                        if (layerType == LAYER_TYPE_NONE) {
-                            final int scrollX = hasDisplayList ? 0 : sx;
-                            final int scrollY = hasDisplayList ? 0 : sy;
-                            canvas.saveLayerAlpha(scrollX, scrollY, scrollX + cr - cl,
-                                    scrollY + cb - ct, multipliedAlpha, layerFlags);
-                        }
-                    } else {
-                        // Alpha is handled by the child directly, clobber the layer's alpha
-                        child.mPrivateFlags |= ALPHA_SET;
-                    }
-                }
-            }
-        } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
-            child.onSetAlpha(255);
-            child.mPrivateFlags &= ~ALPHA_SET;
-        }
-
-        if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
-            if (offsetForScroll) {
-                canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
-            } else {
-                if (!scalingRequired || cache == null) {
-                    canvas.clipRect(0, 0, cr - cl, cb - ct);
-                } else {
-                    canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
-                }
-            }
-        }
-
-        if (hasDisplayList) {
-            displayList = child.getDisplayList();
-            if (!displayList.isValid()) {
-                // Uncommon, but possible. If a view is removed from the hierarchy during the call
-                // to getDisplayList(), the display list will be marked invalid and we should not
-                // try to use it again.
-                displayList = null;
-                hasDisplayList = false;
-            }
-        }
-
-        if (hasNoCache) {
-            boolean layerRendered = false;
-            if (layerType == LAYER_TYPE_HARDWARE) {
-                final HardwareLayer layer = child.getHardwareLayer();
-                if (layer != null && layer.isValid()) {
-                    child.mLayerPaint.setAlpha((int) (alpha * 255));                    
-                    ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint);
-                    layerRendered = true;
-                } else {
-                    final int scrollX = hasDisplayList ? 0 : sx;
-                    final int scrollY = hasDisplayList ? 0 : sy;                    
-                    canvas.saveLayer(scrollX, scrollY,
-                            scrollX + cr - cl, scrollY + cb - ct, child.mLayerPaint,
-                            Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
-                }
-            }
-
-            if (!layerRendered) {
-                if (!hasDisplayList) {
-                    // Fast path for layouts with no backgrounds
-                    if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
-                        if (ViewDebug.TRACE_HIERARCHY) {
-                            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
-                        }
-                        child.mPrivateFlags &= ~DIRTY_MASK;
-                        child.dispatchDraw(canvas);
-                    } else {
-                        child.draw(canvas);
-                    }
-                } else {
-                    child.mPrivateFlags &= ~DIRTY_MASK;
-                    ((HardwareCanvas) canvas).drawDisplayList(displayList, cr - cl, cb - ct, null);
-                }
-            }
-        } else if (cache != null) {
-            child.mPrivateFlags &= ~DIRTY_MASK;
-            Paint cachePaint;
-
-            if (layerType == LAYER_TYPE_NONE) {
-                cachePaint = mCachePaint;
-                if (cachePaint == null) {
-                    cachePaint = new Paint();
-                    cachePaint.setDither(false);
-                    mCachePaint = cachePaint;
-                }
-                if (alpha < 1.0f) {
-                    cachePaint.setAlpha((int) (alpha * 255));
-                    mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
-                } else if  ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
-                    cachePaint.setAlpha(255);
-                    mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
-                }
-            } else {
-                cachePaint = child.mLayerPaint;
-                cachePaint.setAlpha((int) (alpha * 255));
-            }
-            canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
-        }
-
-        canvas.restoreToCount(restoreTo);
-
-        if (a != null && !more) {
-            if (!hardwareAccelerated && !a.getFillAfter()) {
-                child.onSetAlpha(255);
-            }
-            finishAnimatingView(child, a);
-        }
-
-        if (more && hardwareAccelerated) {
-            // invalidation is the trigger to recreate display lists, so if we're using
-            // display lists to render, force an invalidate to allow the animation to
-            // continue drawing another frame
-            invalidate(true);
-            if (a.hasAlpha() && (child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
-                // alpha animations should cause the child to recreate its display list
-                child.invalidate(true);
-            }
-        }
-
-        child.mRecreateDisplayList = false;
-
-        return more;
+        return child.draw(canvas, this, drawingTime);
     }
 
     /**
@@ -3352,6 +3028,11 @@
     private void addViewInner(View child, int index, LayoutParams params,
             boolean preventRequestLayout) {
 
+        if (getAccessibilityNodeProvider() != null) {
+            throw new IllegalStateException("Views with AccessibilityNodeProvider"
+                    + " can't have children.");
+        }
+
         if (mTransition != null) {
             // Don't prevent other add transitions from completing, but cancel remove
             // transitions to let them complete the process before we add to the container
@@ -4845,7 +4526,7 @@
      * @param view The view whose animation has finished
      * @param animation The animation, cannot be null
      */
-    private void finishAnimatingView(final View view, Animation animation) {
+    void finishAnimatingView(final View view, Animation animation) {
         final ArrayList<View> disappearingChildren = mDisappearingChildren;
         if (disappearingChildren != null) {
             if (disappearingChildren.contains(view)) {
@@ -5194,6 +4875,10 @@
         return true;
     }
 
+    /** @hide */
+    protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
+    }
+
     /**
      * LayoutParams are used by views to tell their parents how they want to be
      * laid out. See
@@ -5402,29 +5087,33 @@
      */
     public static class MarginLayoutParams extends ViewGroup.LayoutParams {
         /**
-         * The left margin in pixels of the child. Whenever this value is changed, a call to
-         * {@link android.view.View#requestLayout()} needs to be done.
+         * The left margin in pixels of the child.
+         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+         * to this field.
          */
         @ViewDebug.ExportedProperty(category = "layout")
         public int leftMargin;
 
         /**
-         * The top margin in pixels of the child. Whenever this value is changed, a call to
-         * {@link android.view.View#requestLayout()} needs to be done.
+         * The top margin in pixels of the child.
+         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+         * to this field.
          */
         @ViewDebug.ExportedProperty(category = "layout")
         public int topMargin;
 
         /**
-         * The right margin in pixels of the child. Whenever this value is changed, a call to
-         * {@link android.view.View#requestLayout()} needs to be done.
+         * The right margin in pixels of the child.
+         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+         * to this field.
          */
         @ViewDebug.ExportedProperty(category = "layout")
         public int rightMargin;
 
         /**
-         * The bottom margin in pixels of the child. Whenever this value is changed, a call to
-         * {@link android.view.View#requestLayout()} needs to be done.
+         * The bottom margin in pixels of the child.
+         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+         * to this field.
          */
         @ViewDebug.ExportedProperty(category = "layout")
         public int bottomMargin;
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 89a1ef2..0fdcd0f 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -113,6 +113,10 @@
      * on that list are added to the list of properties associated with that animator.
      */
     ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
+    private Runnable mPendingSetupAction;
+    private Runnable mPendingCleanupAction;
+    private Runnable mPendingOnStartAction;
+    private Runnable mPendingOnEndAction;
 
     /**
      * Constants used to associate a property being requested and the mechanism used to set
@@ -199,6 +203,10 @@
      */
     private HashMap<Animator, PropertyBundle> mAnimatorMap =
             new HashMap<Animator, PropertyBundle>();
+    private HashMap<Animator, Runnable> mAnimatorSetupMap;
+    private HashMap<Animator, Runnable> mAnimatorCleanupMap;
+    private HashMap<Animator, Runnable> mAnimatorOnStartMap;
+    private HashMap<Animator, Runnable> mAnimatorOnEndMap;
 
     /**
      * This is the information we need to set each property during the animation.
@@ -614,6 +622,93 @@
     }
 
     /**
+     * The View associated with this ViewPropertyAnimator will have its
+     * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
+     * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation. This state
+     * is not persistent, either on the View or on this ViewPropertyAnimator: the layer type
+     * of the View will be restored when the animation ends to what it was when this method was
+     * called, and this setting on ViewPropertyAnimator is only valid for the next animation.
+     * Note that calling this method and then independently setting the layer type of the View
+     * (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will result
+     * in some inconsistency, including having the layer type restored to its pre-withLayer()
+     * value when the animation ends.
+     *
+     * @see View#setLayerType(int, android.graphics.Paint)
+     * @return This object, allowing calls to methods in this class to be chained.
+     */
+    public ViewPropertyAnimator withLayer() {
+         mPendingSetupAction= new Runnable() {
+            @Override
+            public void run() {
+                mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            }
+        };
+        final int currentLayerType = mView.getLayerType();
+        mPendingCleanupAction = new Runnable() {
+            @Override
+            public void run() {
+                mView.setLayerType(currentLayerType, null);
+            }
+        };
+        if (mAnimatorSetupMap == null) {
+            mAnimatorSetupMap = new HashMap<Animator, Runnable>();
+        }
+        if (mAnimatorCleanupMap == null) {
+            mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
+        }
+
+        return this;
+    }
+
+    /**
+     * Specifies an action to take place when the next animation runs. If there is a
+     * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
+     * action will run after that startDelay expires, when the actual animation begins.
+     * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
+     * choreographing ViewPropertyAnimator animations with other animations or actions
+     * in the application.
+     *
+     * @param runnable The action to run when the next animation starts.
+     * @return This object, allowing calls to methods in this class to be chained.
+     */
+    public ViewPropertyAnimator withStartAction(Runnable runnable) {
+        mPendingOnStartAction = runnable;
+        if (runnable != null && mAnimatorOnStartMap == null) {
+            mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
+        }
+        return this;
+    }
+
+    /**
+     * Specifies an action to take place when the next animation ends. The action is only
+     * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
+     * that animation, the runnable will not run.
+     * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
+     * choreographing ViewPropertyAnimator animations with other animations or actions
+     * in the application.
+     *
+     * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
+     * <pre>
+     *     Runnable endAction = new Runnable() {
+     *         public void run() {
+     *             view.animate().x(0);
+     *         }
+     *     };
+     *     view.animate().x(200).onEnd(endAction);
+     * </pre>
+     *
+     * @param runnable The action to run when the next animation ends.
+     * @return This object, allowing calls to methods in this class to be chained.
+     */
+    public ViewPropertyAnimator withEndAction(Runnable runnable) {
+        mPendingOnEndAction = runnable;
+        if (runnable != null && mAnimatorOnEndMap == null) {
+            mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
+        }
+        return this;
+    }
+
+    /**
      * Starts the underlying Animator for a set of properties. We use a single animator that
      * simply runs from 0 to 1, and then use that fractional value to set each property
      * value accordingly.
@@ -630,6 +725,22 @@
             propertyMask |= nameValuesHolder.mNameConstant;
         }
         mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
+        if (mPendingSetupAction != null) {
+            mAnimatorSetupMap.put(animator, mPendingSetupAction);
+            mPendingSetupAction = null;
+        }
+        if (mPendingCleanupAction != null) {
+            mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
+            mPendingCleanupAction = null;
+        }
+        if (mPendingOnStartAction != null) {
+            mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
+            mPendingOnStartAction = null;
+        }
+        if (mPendingOnEndAction != null) {
+            mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
+            mPendingOnEndAction = null;
+        }
         animator.addUpdateListener(mAnimatorEventListener);
         animator.addListener(mAnimatorEventListener);
         if (mStartDelaySet) {
@@ -800,6 +911,20 @@
             implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
         @Override
         public void onAnimationStart(Animator animation) {
+            if (mAnimatorSetupMap != null) {
+                Runnable r = mAnimatorSetupMap.get(animation);
+                if (r != null) {
+                    r.run();
+                }
+                mAnimatorSetupMap.remove(animation);
+            }
+            if (mAnimatorOnStartMap != null) {
+                Runnable r = mAnimatorOnStartMap.get(animation);
+                if (r != null) {
+                    r.run();
+                }
+                mAnimatorOnStartMap.remove(animation);
+            }
             if (mListener != null) {
                 mListener.onAnimationStart(animation);
             }
@@ -810,6 +935,9 @@
             if (mListener != null) {
                 mListener.onAnimationCancel(animation);
             }
+            if (mAnimatorOnEndMap != null) {
+                mAnimatorOnEndMap.remove(animation);
+            }
         }
 
         @Override
@@ -824,6 +952,20 @@
             if (mListener != null) {
                 mListener.onAnimationEnd(animation);
             }
+            if (mAnimatorOnEndMap != null) {
+                Runnable r = mAnimatorOnEndMap.get(animation);
+                if (r != null) {
+                    r.run();
+                }
+                mAnimatorOnEndMap.remove(animation);
+            }
+            if (mAnimatorCleanupMap != null) {
+                Runnable r = mAnimatorCleanupMap.get(animation);
+                if (r != null) {
+                    r.run();
+                }
+                mAnimatorCleanupMap.remove(animation);
+            }
             mAnimatorMap.remove(animation);
         }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1a4bdf4..1c3bbfa 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -18,11 +18,13 @@
 
 import android.Manifest;
 import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
 import android.app.ActivityManagerNative;
 import android.content.ClipDescription;
 import android.content.ComponentCallbacks;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -52,6 +54,7 @@
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.Pool;
 import android.util.Poolable;
 import android.util.PoolableManager;
@@ -81,7 +84,6 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -139,6 +141,10 @@
     static final ArrayList<ComponentCallbacks> sConfigCallbacks
             = new ArrayList<ComponentCallbacks>();
 
+    private static boolean sUseRenderThread = false;
+    private static boolean sRenderThreadQueried = false;
+    private static final Object[] sRenderThreadQueryLock = new Object[0];
+
     long mLastTrackballTime = 0;
     final TrackballAxis mTrackballAxisX = new TrackballAxis();
     final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -301,6 +307,8 @@
 
     SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
 
+    AccessibilityPrefetchStrategy mAccessibilityPrefetchStrategy;
+
     private final int mDensity;
 
     /**
@@ -315,8 +323,11 @@
             if (!mInitialized) {
                 try {
                     InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
-                    sWindowSession = Display.getWindowManager().openSession(
+                    IWindowManager windowManager = Display.getWindowManager();
+                    sWindowSession = windowManager.openSession(
                             imm.getClient(), imm.getInputContext());
+                    float animatorScale = windowManager.getAnimationScale(2);
+                    ValueAnimator.setDurationScale(animatorScale);
                     mInitialized = true;
                 } catch (RemoteException e) {
                 }
@@ -377,6 +388,31 @@
         mChoreographer = Choreographer.getInstance();
     }
 
+    /**
+     * @return True if the application requests the use of a separate render thread,
+     *         false otherwise
+     */
+    private static boolean isRenderThreadRequested(Context context) {
+        synchronized (sRenderThreadQueryLock) {
+            if (!sRenderThreadQueried) {
+                final PackageManager packageManager = context.getPackageManager();
+                final String packageName = context.getApplicationInfo().packageName;
+                try {
+                    ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
+                            PackageManager.GET_META_DATA);
+                    if (applicationInfo.metaData != null) {
+                        sUseRenderThread = applicationInfo.metaData.getBoolean(
+                                "android.graphics.renderThread", false);
+                    }
+                } catch (PackageManager.NameNotFoundException e) {
+                } finally {
+                    sRenderThreadQueried = true;
+                }
+            }
+            return sUseRenderThread;
+        }
+    }
+
     public static void addFirstDrawHandler(Runnable callback) {
         synchronized (sFirstDrawHandlers) {
             if (!sFirstDrawComplete) {
@@ -447,7 +483,7 @@
 
                 // If the application owns the surface, don't enable hardware acceleration
                 if (mSurfaceHolder == null) {
-                    enableHardwareAcceleration(attrs);
+                    enableHardwareAcceleration(mView.getContext(), attrs);
                 }
 
                 boolean restore = false;
@@ -607,7 +643,7 @@
         }
     }
 
-    private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
+    private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
         mAttachInfo.mHardwareAccelerated = false;
         mAttachInfo.mHardwareAccelerationRequested = false;
 
@@ -640,20 +676,27 @@
             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
                     && forceHwAccelerated)) {
                 // Don't enable hardware acceleration when we're not on the main thread
-                if (!HardwareRenderer.sSystemRendererDisabled
-                        && Looper.getMainLooper() != Looper.myLooper()) {
-                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+                if (!HardwareRenderer.sSystemRendererDisabled &&
+                        Looper.getMainLooper() != Looper.myLooper()) {
+                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware " 
                             + "acceleration outside of the main thread, aborting");
                     return;
                 }
 
-                final boolean translucent = attrs.format != PixelFormat.OPAQUE;
+                boolean renderThread = isRenderThreadRequested(context);
+                if (renderThread) {
+                    Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
+                }
+
                 if (mAttachInfo.mHardwareRenderer != null) {
                     mAttachInfo.mHardwareRenderer.destroy(true);
-                }                
+                }
+
+                final boolean translucent = attrs.format != PixelFormat.OPAQUE;
                 mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
                 mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
                         = mAttachInfo.mHardwareRenderer != null;
+
             } else if (fakeHwAccelerated) {
                 // The window had wanted to use hardware acceleration, but this
                 // is not allowed in its process.  By setting this flag, it can
@@ -807,6 +850,11 @@
 
     @Override
     public void onDraw() {
+        if (mInputEventReceiver != null) {
+            mInputEventReceiver.consumeBatchedInputEvents();
+        }
+        doProcessInputEvents();
+
         if (mTraversalScheduled) {
             mTraversalScheduled = false;
             doTraversal();
@@ -847,8 +895,6 @@
     }
 
     private void doTraversal() {
-        doProcessInputEvents();
-
         if (mProfile) {
             Debug.startMethodTracing("ViewAncestor");
         }
@@ -2586,7 +2632,7 @@
             break;
         case DISPATCH_KEY: {
             KeyEvent event = (KeyEvent)msg.obj;
-            enqueueInputEvent(event, null, 0);
+            enqueueInputEvent(event, null, 0, true);
         } break;
         case DISPATCH_KEY_FROM_IME: {
             if (LOCAL_LOGV) Log.v(
@@ -2599,7 +2645,7 @@
                 //noinspection UnusedAssignment
                 event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
             }
-            enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME);
+            enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
         } break;
         case FINISH_INPUT_CONNECTION: {
             InputMethodManager imm = InputMethodManager.peekInstance();
@@ -2901,7 +2947,7 @@
             case MotionEvent.ACTION_DOWN:
                 x.reset(2);
                 y.reset(2);
-                dispatchKey(new KeyEvent(curTime, curTime,
+                enqueueInputEvent(new KeyEvent(curTime, curTime,
                         KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
                         InputDevice.SOURCE_KEYBOARD));
@@ -2909,7 +2955,7 @@
             case MotionEvent.ACTION_UP:
                 x.reset(2);
                 y.reset(2);
-                dispatchKey(new KeyEvent(curTime, curTime,
+                enqueueInputEvent(new KeyEvent(curTime, curTime,
                         KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
                         InputDevice.SOURCE_KEYBOARD));
@@ -2963,7 +3009,7 @@
                         + keycode);
                 movement--;
                 int repeatCount = accelMovement - movement;
-                dispatchKey(new KeyEvent(curTime, curTime,
+                enqueueInputEvent(new KeyEvent(curTime, curTime,
                         KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
                         InputDevice.SOURCE_KEYBOARD));
@@ -2973,11 +3019,11 @@
                         + keycode);
                 movement--;
                 curTime = SystemClock.uptimeMillis();
-                dispatchKey(new KeyEvent(curTime, curTime,
+                enqueueInputEvent(new KeyEvent(curTime, curTime,
                         KeyEvent.ACTION_DOWN, keycode, 0, metaState,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
                         InputDevice.SOURCE_KEYBOARD));
-                dispatchKey(new KeyEvent(curTime, curTime,
+                enqueueInputEvent(new KeyEvent(curTime, curTime,
                         KeyEvent.ACTION_UP, keycode, 0, metaState,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
                         InputDevice.SOURCE_KEYBOARD));
@@ -3044,7 +3090,7 @@
 
         if (xDirection != mLastJoystickXDirection) {
             if (mLastJoystickXKeyCode != 0) {
-                dispatchKey(new KeyEvent(time, time,
+                enqueueInputEvent(new KeyEvent(time, time,
                         KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
                 mLastJoystickXKeyCode = 0;
@@ -3055,7 +3101,7 @@
             if (xDirection != 0 && synthesizeNewKeys) {
                 mLastJoystickXKeyCode = xDirection > 0
                         ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
-                dispatchKey(new KeyEvent(time, time,
+                enqueueInputEvent(new KeyEvent(time, time,
                         KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
             }
@@ -3063,7 +3109,7 @@
 
         if (yDirection != mLastJoystickYDirection) {
             if (mLastJoystickYKeyCode != 0) {
-                dispatchKey(new KeyEvent(time, time,
+                enqueueInputEvent(new KeyEvent(time, time,
                         KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
                 mLastJoystickYKeyCode = 0;
@@ -3074,7 +3120,7 @@
             if (yDirection != 0 && synthesizeNewKeys) {
                 mLastJoystickYKeyCode = yDirection > 0
                         ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
-                dispatchKey(new KeyEvent(time, time,
+                enqueueInputEvent(new KeyEvent(time, time,
                         KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
                         deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
             }
@@ -3438,11 +3484,11 @@
         if (args.localChanges != 0) {
             if (mAttachInfo != null) {
                 mAttachInfo.mSystemUiVisibility =
-                        (mAttachInfo.mSystemUiVisibility&~args.localChanges)
-                        | (args.localValue&args.localChanges);
+                        (mAttachInfo.mSystemUiVisibility & ~args.localChanges) |
+                                (args.localValue & args.localChanges);
+                mAttachInfo.mRecomputeGlobalAttributes = true;
             }
             mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
-            mAttachInfo.mRecomputeGlobalAttributes = true;
             scheduleTraversals();            
         }
         mView.dispatchSystemUiVisibilityChanged(args.globalVisibility);
@@ -3480,6 +3526,17 @@
         return mAccessibilityInteractionController;
     }
 
+    public AccessibilityPrefetchStrategy getAccessibilityPrefetchStrategy() {
+        if (mView == null) {
+            throw new IllegalStateException("getAccessibilityPrefetchStrategy"
+                    + " called when there is no mView");
+        }
+        if (mAccessibilityPrefetchStrategy == null) {
+            mAccessibilityPrefetchStrategy = new AccessibilityPrefetchStrategy();
+        }
+        return mAccessibilityPrefetchStrategy;
+    }
+
     private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
             boolean insetsPending) throws RemoteException {
 
@@ -3585,7 +3642,7 @@
         mView.debug();
     }
     
-    public void dumpGfxInfo(PrintWriter pw, int[] info) {
+    public void dumpGfxInfo(int[] info) {
         if (mView != null) {
             getGfxInfo(mView, info);
         } else {
@@ -3697,7 +3754,7 @@
      * Represents a pending input event that is waiting in a queue.
      *
      * Input events are processed in serial order by the timestamp specified by
-     * {@link InputEvent#getEventTime()}.  In general, the input dispatcher delivers
+     * {@link InputEvent#getEventTimeNano()}.  In general, the input dispatcher delivers
      * one input event to the application at a time and waits for the application
      * to finish handling it before delivering the next one.
      *
@@ -3706,7 +3763,7 @@
      * needing a queue on the application's side.
      */
     private static final class QueuedInputEvent {
-        public static final int FLAG_DELIVER_POST_IME = 1 << 0;
+        public static final int FLAG_DELIVER_POST_IME = 1;
 
         public QueuedInputEvent mNext;
 
@@ -3748,8 +3805,12 @@
         }
     }
 
+    void enqueueInputEvent(InputEvent event) {
+        enqueueInputEvent(event, null, 0, false);
+    }
+
     void enqueueInputEvent(InputEvent event,
-            InputEventReceiver receiver, int flags) {
+            InputEventReceiver receiver, int flags, boolean processImmediately) {
         QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
 
         if (ViewDebug.DEBUG_LATENCY) {
@@ -3773,7 +3834,11 @@
             last.mNext = q;
         }
 
-        scheduleProcessInputEvents();
+        if (processImmediately) {
+            doProcessInputEvents();
+        } else {
+            scheduleProcessInputEvents();
+        }
     }
 
     private void scheduleProcessInputEvents() {
@@ -3862,13 +3927,19 @@
 
         @Override
         public void onInputEvent(InputEvent event) {
-            enqueueInputEvent(event, this, 0);
+            enqueueInputEvent(event, this, 0, true);
+        }
+
+        @Override
+        public void onBatchedInputEventPending() {
+            mChoreographer.scheduleDraw();
         }
     }
     WindowInputEventReceiver mInputEventReceiver;
 
     public void dispatchKey(KeyEvent event) {
-        enqueueInputEvent(event, null, 0);
+        Message msg = obtainMessage(DISPATCH_KEY, event);
+        sendMessage(msg);
     }
 
     public void dispatchAppVisibility(boolean visible) {
@@ -3980,6 +4051,7 @@
         if (mView == null) {
             return false;
         }
+        getAccessibilityPrefetchStrategy().onAccessibilityEvent(event);
         mAccessibilityManager.sendAccessibilityEvent(event);
         return true;
     }
@@ -4539,6 +4611,13 @@
                 viewRootImpl.getAccessibilityInteractionController()
                     .findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
                         interactionId, callback, interrogatingPid, interrogatingTid);
+            } else {
+                // We cannot make the call and notify the caller so it does not wait.
+                try {
+                    callback.setFindAccessibilityNodeInfosResult(null, interactionId);
+                } catch (RemoteException re) {
+                    /* best effort - ignore */
+                }
             }
         }
 
@@ -4550,28 +4629,49 @@
                 viewRootImpl.getAccessibilityInteractionController()
                     .performAccessibilityActionClientThread(accessibilityNodeId, action,
                             interactionId, callback, interogatingPid, interrogatingTid);
+            } else {
+                // We cannot make the call and notify the caller so it does not
+                try {
+                    callback.setPerformAccessibilityActionResult(false, interactionId);
+                } catch (RemoteException re) {
+                    /* best effort - ignore */
+                }
             }
         }
 
-        public void findAccessibilityNodeInfoByViewId(int viewId,
+        public void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
                 int interrogatingPid, long interrogatingTid) {
             ViewRootImpl viewRootImpl = mViewRootImpl.get();
             if (viewRootImpl != null && viewRootImpl.mView != null) {
                 viewRootImpl.getAccessibilityInteractionController()
-                    .findAccessibilityNodeInfoByViewIdClientThread(viewId, interactionId, callback,
-                            interrogatingPid, interrogatingTid);
-            }
-        }
-
-        public void findAccessibilityNodeInfosByText(String text, long accessibilityNodeId,
-                int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                int interrogatingPid, long interrogatingTid) {
-            ViewRootImpl viewRootImpl = mViewRootImpl.get();
-            if (viewRootImpl != null && viewRootImpl.mView != null) {
-                viewRootImpl.getAccessibilityInteractionController()
-                    .findAccessibilityNodeInfosByTextClientThread(text, accessibilityNodeId,
+                    .findAccessibilityNodeInfoByViewIdClientThread(accessibilityNodeId, viewId,
                             interactionId, callback, interrogatingPid, interrogatingTid);
+            } else {
+                // We cannot make the call and notify the caller so it does not
+                try {
+                    callback.setFindAccessibilityNodeInfoResult(null, interactionId);
+                } catch (RemoteException re) {
+                    /* best effort - ignore */
+                }
+            }
+        }
+
+        public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
+                int interactionId, IAccessibilityInteractionConnectionCallback callback,
+                int interrogatingPid, long interrogatingTid) {
+            ViewRootImpl viewRootImpl = mViewRootImpl.get();
+            if (viewRootImpl != null && viewRootImpl.mView != null) {
+                viewRootImpl.getAccessibilityInteractionController()
+                    .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
+                            interactionId, callback, interrogatingPid, interrogatingTid);
+            } else {
+                // We cannot make the call and notify the caller so it does not
+                try {
+                    callback.setFindAccessibilityNodeInfosResult(null, interactionId);
+                } catch (RemoteException re) {
+                    /* best effort - ignore */
+                }
             }
         }
     }
@@ -4649,6 +4749,7 @@
                 long interrogatingTid) {
             Message message = Message.obtain();
             message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+            message.arg1 = interrogatingPid;
             SomeArgs args = mPool.acquire();
             args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
             args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
@@ -4671,40 +4772,47 @@
 
         public void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
             SomeArgs args = (SomeArgs) message.obj;
+            final int interrogatingPid = message.arg1;
             final int accessibilityViewId = args.argi1;
             final int virtualDescendantId = args.argi2;
             final int interactionId = args.argi3;
             final IAccessibilityInteractionConnectionCallback callback =
                 (IAccessibilityInteractionConnectionCallback) args.arg1;
             mPool.release(args);
-            AccessibilityNodeInfo info = null;
+            List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+            infos.clear();
             try {
                 View target = findViewByAccessibilityId(accessibilityViewId);
                 if (target != null && target.getVisibility() == View.VISIBLE) {
                     AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
                     if (provider != null) {
-                        info = provider.createAccessibilityNodeInfo(virtualDescendantId);
+                        infos.add(provider.createAccessibilityNodeInfo(virtualDescendantId));
                     } else if (virtualDescendantId == View.NO_ID) {
-                        info = target.createAccessibilityNodeInfo();
+                        getAccessibilityPrefetchStrategy().prefetchAccessibilityNodeInfos(
+                                interrogatingPid, target, infos);
                     }
                 }
             } finally {
                 try {
-                    callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+                    callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
+                    infos.clear();
                 } catch (RemoteException re) {
                     /* ignore - the other side will time out */
                 }
             }
         }
 
-        public void findAccessibilityNodeInfoByViewIdClientThread(int viewId, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
-                long interrogatingTid) {
+        public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId,
+                int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+                int interrogatingPid, long interrogatingTid) {
             Message message = Message.obtain();
             message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
-            message.arg1 = viewId;
-            message.arg2 = interactionId;
-            message.obj = callback;
+            message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+            SomeArgs args = mPool.acquire();
+            args.argi1 = viewId;
+            args.argi2 = interactionId;
+            args.arg1 = callback;
+            message.obj = args;
             // If the interrogation is performed by the same thread as the main UI
             // thread in this process, set the message as a static reference so
             // after this call completes the same thread but in the interrogating
@@ -4720,17 +4828,26 @@
         }
 
         public void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
-            final int viewId = message.arg1;
-            final int interactionId = message.arg2;
+            final int accessibilityViewId = message.arg1;
+            SomeArgs args = (SomeArgs) message.obj;
+            final int viewId = args.argi1;
+            final int interactionId = args.argi2;
             final IAccessibilityInteractionConnectionCallback callback =
-                (IAccessibilityInteractionConnectionCallback) message.obj;
-
+                (IAccessibilityInteractionConnectionCallback) args.arg1;
+            mPool.release(args);
             AccessibilityNodeInfo info = null;
             try {
-                View root = ViewRootImpl.this.mView;
-                View target = root.findViewById(viewId);
-                if (target != null && target.getVisibility() == View.VISIBLE) {
-                    info = target.createAccessibilityNodeInfo();
+                View root = null;
+                if (accessibilityViewId != View.NO_ID) {
+                    root = findViewByAccessibilityId(accessibilityViewId);
+                } else {
+                    root = ViewRootImpl.this.mView;
+                }
+                if (root != null) {
+                    View target = root.findViewById(viewId);
+                    if (target != null && target.getVisibility() == View.VISIBLE) {
+                        info = target.createAccessibilityNodeInfo();
+                    }
                 }
             } finally {
                 try {
@@ -4741,8 +4858,8 @@
             }
         }
 
-        public void findAccessibilityNodeInfosByTextClientThread(String text,
-                long accessibilityNodeId, int interactionId,
+        public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId,
+                String text, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
                 long interrogatingTid) {
             Message message = Message.obtain();
@@ -4779,7 +4896,7 @@
             mPool.release(args);
             List<AccessibilityNodeInfo> infos = null;
             try {
-                View target = null;
+                View target;
                 if (accessibilityViewId != View.NO_ID) {
                     target = findViewByAccessibilityId(accessibilityViewId);
                 } else {
@@ -4934,4 +5051,88 @@
             }
         }
     }
+
+    /**
+     * This class encapsulates a prefetching strategy for the accessibility APIs for
+     * querying window content.It is responsible to prefetch a batch of
+     * AccessibilityNodeInfos in addition to the one for a requested node. It caches
+     * the ids of the prefeteched nodes such that they are fetched only once.
+     */
+    class AccessibilityPrefetchStrategy {
+        private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 100;
+
+        // We need to keep track of what we have sent for each interrogating
+        // process. Usually there will be only one such process but we
+        // should support the general case. Note that the accessibility event
+        // stream will take care of clearing caches of querying processes that
+        // are not longer alive, so we do not waste memory.
+        private final LongSparseArray<AccessibilityNodeInfoCache> mAccessibilityNodeInfoCaches =
+            new LongSparseArray<AccessibilityNodeInfoCache>();
+
+        private AccessibilityNodeInfoCache getCacheForInterrogatingPid(long interrogatingPid) {
+            AccessibilityNodeInfoCache cache = mAccessibilityNodeInfoCaches.get(interrogatingPid);
+            if (cache == null) {
+                cache = AccessibilityNodeInfoCache.newAccessibilityNodeInfoCache();
+                mAccessibilityNodeInfoCaches.put(interrogatingPid, cache);
+            }
+            return cache;
+        }
+
+        public void onAccessibilityEvent(AccessibilityEvent event) {
+            final int cacheCount = mAccessibilityNodeInfoCaches.size();
+            for (int i = 0; i < cacheCount; i++) {
+                AccessibilityNodeInfoCache cache = mAccessibilityNodeInfoCaches.valueAt(i);
+                cache.onAccessibilityEvent(event);
+            }
+        }
+
+        public void prefetchAccessibilityNodeInfos(long interrogatingPid, View root,
+                List<AccessibilityNodeInfo> outInfos) {
+            addAndCacheNotCachedNodeInfo(interrogatingPid, root, outInfos);
+            addAndCacheNotCachedPredecessorInfos(interrogatingPid, root, outInfos);
+            addAndCacheNotCachedDescendantInfos(interrogatingPid, root, outInfos);
+        }
+
+        private void addAndCacheNotCachedNodeInfo(long interrogatingPid,
+                View view, List<AccessibilityNodeInfo> outInfos) {
+            final long accessibilityNodeId = AccessibilityNodeInfo.makeNodeId(
+                    view.getAccessibilityViewId(), View.NO_ID);
+            AccessibilityNodeInfoCache cache = getCacheForInterrogatingPid(interrogatingPid);
+            if (!cache.containsKey(accessibilityNodeId)) {
+                // Account for the ids of the fetched infos. The infos will be
+                // cached in the window querying process. We just need to know
+                // which infos are cached to avoid fetching a cached one again.
+                cache.put(accessibilityNodeId, null);
+                outInfos.add(view.createAccessibilityNodeInfo());
+            }
+        }
+
+        private void addAndCacheNotCachedPredecessorInfos(long interrogatingPid, View view,
+                List<AccessibilityNodeInfo> outInfos) {
+            ViewParent predecessor = view.getParent();
+            while (predecessor instanceof View
+                    && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+                View predecessorView = (View) predecessor;
+                addAndCacheNotCachedNodeInfo(interrogatingPid, predecessorView, outInfos);
+                predecessor = predecessor.getParent();
+            }
+        }
+
+        private void addAndCacheNotCachedDescendantInfos(long interrogatingPid, View view,
+                List<AccessibilityNodeInfo> outInfos) {
+            if (outInfos.size() > MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE
+                    || view.getAccessibilityNodeProvider() != null) {
+                return;
+            }
+            addAndCacheNotCachedNodeInfo(interrogatingPid, view, outInfos);
+            if (view instanceof ViewGroup) {
+                ViewGroup rootGroup = (ViewGroup) view;
+                final int childCount = rootGroup.getChildCount();
+                for (int i = 0; i < childCount; i++) {
+                View child = rootGroup.getChildAt(i);
+                    addAndCacheNotCachedDescendantInfos(interrogatingPid, child, outInfos);
+                }
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 24a3066..9152cc3 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -91,6 +91,10 @@
     private static final int MSG_VIBRATE = 4;
     private static final int MSG_TIMEOUT = 5;
     private static final int MSG_RINGER_MODE_CHANGED = 6;
+    private static final int MSG_MUTE_CHANGED = 7;
+
+    // Pseudo stream type for master volume
+    private static final int STREAM_MASTER = -100;
 
     protected Context mContext;
     private AudioManager mAudioManager;
@@ -148,7 +152,13 @@
                 R.string.volume_icon_description_notification,
                 R.drawable.ic_audio_notification,
                 R.drawable.ic_audio_notification_mute,
-                true);
+                true),
+        // for now, use media resources for master volume
+        MasterStream(STREAM_MASTER,
+                R.string.volume_icon_description_media,
+                R.drawable.ic_audio_vol,
+                R.drawable.ic_audio_vol_mute,
+                false);
 
         int streamType;
         int descRes;
@@ -173,7 +183,8 @@
         StreamResources.VoiceStream,
         StreamResources.MediaStream,
         StreamResources.NotificationStream,
-        StreamResources.AlarmStream
+        StreamResources.AlarmStream,
+        StreamResources.MasterStream
     };
 
     /** Object that contains data for each slider */
@@ -195,6 +206,16 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mAudioService = volumeService;
 
+        // For now, only show master volume if master volume is supported
+        boolean useMasterVolume = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_useMasterVolume);
+        if (useMasterVolume) {
+            for (int i = 0; i < STREAMS.length; i++) {
+                StreamResources streamRes = STREAMS[i];
+                streamRes.show = (streamRes.streamType == STREAM_MASTER);
+            }
+        }
+
         LayoutInflater inflater = (LayoutInflater) context
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View view = mView = inflater.inflate(R.layout.volume_adjust, null);
@@ -245,7 +266,7 @@
         mVibrator = new Vibrator();
 
         mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
-        mShowCombinedVolumes = !mVoiceCapable;
+        mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
         // If we don't want to show multiple volumes, hide the settings button and divider
         if (!mShowCombinedVolumes) {
             mMoreButton.setVisibility(View.GONE);
@@ -274,7 +295,43 @@
     }
 
     private boolean isMuted(int streamType) {
-        return mAudioManager.isStreamMute(streamType);
+        if (streamType == STREAM_MASTER) {
+            return mAudioService.isMasterMute();
+        } else {
+            return mAudioService.isStreamMute(streamType);
+        }
+    }
+
+    private int getStreamMaxVolume(int streamType) {
+        if (streamType == STREAM_MASTER) {
+            return mAudioService.getMasterMaxVolume();
+        } else {
+            return mAudioService.getStreamMaxVolume(streamType);
+        }
+    }
+
+    private int getStreamVolume(int streamType) {
+        if (streamType == STREAM_MASTER) {
+            return mAudioService.getMasterVolume();
+        } else {
+            return mAudioService.getStreamVolume(streamType);
+        }
+    }
+
+    private void setStreamVolume(int streamType, int index, int flags) {
+        if (streamType == STREAM_MASTER) {
+            mAudioService.setMasterVolume(index, flags);
+        } else {
+            mAudioService.setStreamVolume(streamType, index, flags);
+        }
+    }
+
+    private int getLastAudibleStreamVolume(int streamType) {
+        if (streamType == STREAM_MASTER) {
+            return mAudioService.getLastAudibleMasterVolume();
+        } else {
+            return mAudioService.getLastAudibleStreamVolume(streamType);
+        }
     }
 
     private void createSliders() {
@@ -301,7 +358,7 @@
             sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
             int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
                     streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
-            sc.seekbarView.setMax(mAudioManager.getStreamMaxVolume(streamType) + plusOne);
+            sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
             sc.seekbarView.setOnSeekBarChangeListener(this);
             sc.seekbarView.setTag(sc);
             mStreamControls.put(streamType, sc);
@@ -342,7 +399,7 @@
 
     /** Update the mute and progress state of a slider */
     private void updateSlider(StreamControl sc) {
-        sc.seekbarView.setProgress(mAudioManager.getLastAudibleStreamVolume(sc.streamType));
+        sc.seekbarView.setProgress(getLastAudibleStreamVolume(sc.streamType));
         final boolean muted = isMuted(sc.streamType);
         sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
         if (sc.streamType == AudioManager.STREAM_RING && muted
@@ -390,6 +447,23 @@
         obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
     }
 
+    public void postMasterVolumeChanged(int flags) {
+        postVolumeChanged(STREAM_MASTER, flags);
+    }
+
+    public void postMuteChanged(int streamType, int flags) {
+        if (hasMessages(MSG_VOLUME_CHANGED)) return;
+        if (mStreamControls == null) {
+            createSliders();
+        }
+        removeMessages(MSG_FREE_RESOURCES);
+        obtainMessage(MSG_MUTE_CHANGED, streamType, flags).sendToTarget();
+    }
+
+    public void postMasterMuteChanged(int flags) {
+        postMuteChanged(STREAM_MASTER, flags);
+    }
+
     /**
      * Override this if you have other work to do when the volume changes (for
      * example, vibrating, playing a sound, etc.). Make sure to call through to
@@ -423,10 +497,22 @@
         resetTimeout();
     }
 
+    protected void onMuteChanged(int streamType, int flags) {
+
+        if (LOGD) Log.d(TAG, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
+
+        StreamControl sc = mStreamControls.get(streamType);
+        if (sc != null) {
+            sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
+        }
+
+        onVolumeChanged(streamType, flags);
+    }
+
     protected void onShowVolumeChanged(int streamType, int flags) {
-        int index = mAudioService.isStreamMute(streamType) ?
-                mAudioService.getLastAudibleStreamVolume(streamType)
-                : mAudioService.getStreamVolume(streamType);
+        int index = isMuted(streamType) ?
+                getLastAudibleStreamVolume(streamType)
+                : getStreamVolume(streamType);
 
         mRingIsSilent = false;
 
@@ -437,7 +523,7 @@
 
         // get max volume for progress bar
 
-        int max = mAudioService.getStreamMaxVolume(streamType);
+        int max = getStreamMaxVolume(streamType);
 
         switch (streamType) {
 
@@ -571,6 +657,7 @@
      * Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
      */
     private ToneGenerator getOrCreateToneGenerator(int streamType) {
+        if (streamType == STREAM_MASTER) return null;
         synchronized (this) {
             if (mToneGenerators[streamType] == null) {
                 try {
@@ -620,6 +707,11 @@
                 break;
             }
 
+            case MSG_MUTE_CHANGED: {
+                onMuteChanged(msg.arg1, msg.arg2);
+                break;
+            }
+
             case MSG_FREE_RESOURCES: {
                 onFreeResources();
                 break;
@@ -671,8 +763,8 @@
         final Object tag = seekBar.getTag();
         if (fromUser && tag instanceof StreamControl) {
             StreamControl sc = (StreamControl) tag;
-            if (mAudioManager.getStreamVolume(sc.streamType) != progress) {
-                mAudioManager.setStreamVolume(sc.streamType, progress, 0);
+            if (getStreamVolume(sc.streamType) != progress) {
+                setStreamVolume(sc.streamType, progress, 0);
             }
         }
         resetTimeout();
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index d7113374..6dbdedb 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -480,9 +480,19 @@
         try {
             synchronized (this) {
                 if (mViews != null) {
-                    pw.println("View hierarchy:");
-
                     final int count = mViews.length;
+                    
+                    pw.println("Profile data in ms:");
+
+                    for (int i = 0; i < count; i++) {
+                        ViewRootImpl root = mRoots[i];
+                        HardwareRenderer renderer = root.getView().mAttachInfo.mHardwareRenderer;
+                        if (renderer != null) {
+                            renderer.dumpGfxInfo(pw);
+                        }
+                    }
+
+                    pw.println("\nView hierarchy:");
 
                     int viewsCount = 0;
                     int displayListsSize = 0;
@@ -490,7 +500,7 @@
 
                     for (int i = 0; i < count; i++) {
                         ViewRootImpl root = mRoots[i];
-                        root.dumpGfxInfo(pw, info);
+                        root.dumpGfxInfo(info);
 
                         String name = root.getClass().getName() + '@' +
                                 Integer.toHexString(hashCode());                        
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 6ec2e8d..75267bb 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -536,7 +536,7 @@
     /**
      * Return the available screen width that we should report for the
      * configuration.  This must be no larger than
-     * {@link #getNonDecorDisplayWidth(int, int)}; it may be smaller than
+     * {@link #getNonDecorDisplayWidth(int, int, int)}; it may be smaller than
      * that to account for more transient decoration like a status bar.
      */
     public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation);
@@ -544,7 +544,7 @@
     /**
      * Return the available screen height that we should report for the
      * configuration.  This must be no larger than
-     * {@link #getNonDecorDisplayHeight(int, int)}; it may be smaller than
+     * {@link #getNonDecorDisplayHeight(int, int, int)}; it may be smaller than
      * that to account for more transient decoration like a status bar.
      */
     public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation);
@@ -754,12 +754,8 @@
      * Called when layout of the windows is finished.  After this function has
      * returned, all windows given to layoutWindow() <em>must</em> have had a
      * frame assigned.
-     *  
-     * @return Return any bit set of {@link #FINISH_LAYOUT_REDO_LAYOUT},
-     * {@link #FINISH_LAYOUT_REDO_CONFIG}, {@link #FINISH_LAYOUT_REDO_WALLPAPER},
-     * or {@link #FINISH_LAYOUT_REDO_ANIM}.
      */
-    public int finishLayoutLw();
+    public void finishLayoutLw();
 
     /** Layout state may have changed (so another layout will be performed) */
     static final int FINISH_LAYOUT_REDO_LAYOUT = 0x0001;
@@ -822,7 +818,7 @@
 
     public interface ScreenOnListener {
         void onScreenOn();
-    };
+    }
 
     /**
      * Called when the power manager would like to turn the screen on.
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 95c070c..072fdd8 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -24,7 +24,9 @@
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.SparseArray;
+import android.view.AccessibilityNodeInfoCache;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -97,6 +99,11 @@
     private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
         new SparseArray<IAccessibilityServiceConnection>();
 
+    // The connection cache is shared between all interrogating threads since
+    // at any given time there is only one window allowing querying.
+    private static final AccessibilityNodeInfoCache sAccessibilityNodeInfoCache =
+        AccessibilityNodeInfoCache.newSynchronizedAccessibilityNodeInfoCache();
+
     /**
      * @return The client for the current thread.
      */
@@ -145,7 +152,9 @@
      * Finds an {@link AccessibilityNodeInfo} by accessibility id.
      *
      * @param connectionId The id of a connection for interacting with the system.
-     * @param accessibilityWindowId A unique window id.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
      * @param accessibilityNodeId A unique node accessibility id
      *     (accessibility view and virtual descendant id).
      * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
@@ -155,16 +164,22 @@
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
+                AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(accessibilityNodeId); 
+                if (cachedInfo != null) {
+                    return cachedInfo;
+                }
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId(
                         accessibilityWindowId, accessibilityNodeId, interactionId, this,
                         Thread.currentThread().getId());
                 // If the scale is zero the call has failed.
                 if (windowScale > 0) {
-                    AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
+                    List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
-                    finalizeAccessibilityNodeInfo(info, connectionId, windowScale);
-                    return info;
+                    finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
+                    if (infos != null && !infos.isEmpty()) {
+                        return infos.get(0);
+                    }
                 }
             } else {
                 if (DEBUG) {
@@ -181,22 +196,30 @@
     }
 
     /**
-     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
-     * in the currently active window and starts from the root View in the window.
+     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+     * the window whose id is specified and starts from the node whose accessibility
+     * id is specified.
      *
      * @param connectionId The id of a connection for interacting with the system.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id from where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     to start from the root.
      * @param viewId The id of the view.
      * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
      */
-    public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int connectionId,
-            int viewId) {
+    public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int connectionId,
+            int accessibilityWindowId, long accessibilityNodeId, int viewId) {
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final float windowScale =
-                    connection.findAccessibilityNodeInfoByViewIdInActiveWindow(viewId,
-                            interactionId, this, Thread.currentThread().getId());
+                    connection.findAccessibilityNodeInfoByViewId(accessibilityWindowId,
+                            accessibilityNodeId, viewId, interactionId, this,
+                            Thread.currentThread().getId());
                 // If the scale is zero the call has failed.
                 if (windowScale > 0) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
@@ -220,64 +243,27 @@
 
     /**
      * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
-     * insensitive containment. The search is performed in the currently
-     * active window and starts from the root View in the window.
-     *
-     * @param connectionId The id of a connection for interacting with the system.
-     * @param text The searched text.
-     * @return A list of found {@link AccessibilityNodeInfo}s.
-     */
-    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByTextInActiveWindow(
-            int connectionId, String text) {
-        try {
-            IAccessibilityServiceConnection connection = getConnection(connectionId);
-            if (connection != null) {
-                final int interactionId = mInteractionIdCounter.getAndIncrement();
-                final float windowScale =
-                    connection.findAccessibilityNodeInfosByTextInActiveWindow(text,
-                            interactionId, this, Thread.currentThread().getId());
-                // If the scale is zero the call has failed.
-                if (windowScale > 0) {
-                    List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
-                            interactionId);
-                    finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
-                    return infos;
-                }
-            } else {
-                if (DEBUG) {
-                    Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
-                }
-            }
-        } catch (RemoteException re) {
-            if (DEBUG) {
-                Log.w(LOG_TAG, "Error while calling remote"
-                        + " findAccessibilityNodeInfosByViewTextInActiveWindow", re);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
      * insensitive containment. The search is performed in the window whose
-     * id is specified and starts from the View whose accessibility id is
+     * id is specified and starts from the node whose accessibility id is
      * specified.
      *
      * @param connectionId The id of a connection for interacting with the system.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
+     * @param accessibilityNodeId A unique view id from where to start the search. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
      * @param text The searched text.
-     * @param accessibilityWindowId A unique window id.
-     * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id) from
-     *        where to start the search. Use {@link android.view.View#NO_ID} to start from the root.
      * @return A list of found {@link AccessibilityNodeInfo}s.
      */
     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int connectionId,
-            String text, int accessibilityWindowId, long accessibilityNodeId) {
+            int accessibilityWindowId, long accessibilityNodeId, String text) {
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
-                final float windowScale = connection.findAccessibilityNodeInfosByText(text,
-                        accessibilityWindowId, accessibilityNodeId, interactionId, this,
+                final float windowScale = connection.findAccessibilityNodeInfosByText(
+                        accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
                         Thread.currentThread().getId());
                 // If the scale is zero the call has failed.
                 if (windowScale > 0) {
@@ -304,7 +290,9 @@
      * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
      *
      * @param connectionId The id of a connection for interacting with the system.
-     * @param accessibilityWindowId The id of the window.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     to query the currently active window.
      * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
      * @param action The action to perform.
      * @return Whether the action was performed.
@@ -319,7 +307,7 @@
                         accessibilityWindowId, accessibilityNodeId, action, interactionId, this,
                         Thread.currentThread().getId());
                 if (success) {
-                    return getPerformAccessibilityActionResult(interactionId);
+                    return getPerformAccessibilityActionResultAndClear(interactionId);
                 }
             } else {
                 if (DEBUG) {
@@ -334,6 +322,24 @@
         return false;
     }
 
+    public void clearCache() {
+        if (DEBUG) {
+            Log.w(LOG_TAG, "clearCache()");
+        }
+        sAccessibilityNodeInfoCache.clear();
+    }
+
+    public void removeCachedNode(long accessibilityNodeId) {
+        if (DEBUG) {
+            Log.w(LOG_TAG, "removeCachedNode(" + accessibilityNodeId +")");
+        }
+        sAccessibilityNodeInfoCache.remove(accessibilityNodeId);
+    }
+
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        sAccessibilityNodeInfoCache.onAccessibilityEvent(event);
+    }
+
     /**
      * Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}.
      *
@@ -358,6 +364,9 @@
             if (interactionId > mInteractionId) {
                 mFindAccessibilityNodeInfoResult = info;
                 mInteractionId = interactionId;
+                if (info != null) {
+                    sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
+                }
             }
             mInstanceLock.notifyAll();
         }
@@ -386,8 +395,20 @@
                 int interactionId) {
         synchronized (mInstanceLock) {
             if (interactionId > mInteractionId) {
-                mFindAccessibilityNodeInfosResult = infos;
+                // If the call is not an IPC, i.e. it is made from the same process, we need to
+                // instantiate new result list to avoid passing internal instances to clients.
+                final boolean isIpcCall = (queryLocalInterface(getInterfaceDescriptor()) == null);
+                if (!isIpcCall) {
+                    mFindAccessibilityNodeInfosResult = new ArrayList<AccessibilityNodeInfo>(infos);
+                } else {
+                    mFindAccessibilityNodeInfosResult = infos;
+                }
                 mInteractionId = interactionId;
+                final int infoCount = infos.size();
+                for (int i = 0; i < infoCount; i ++) {
+                    AccessibilityNodeInfo info = infos.get(i);
+                    sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
+                }
             }
             mInstanceLock.notifyAll();
         }
@@ -399,7 +420,7 @@
      * @param interactionId The interaction id to match the result with the request.
      * @return Whether the action was performed.
      */
-    private boolean getPerformAccessibilityActionResult(int interactionId) {
+    private boolean getPerformAccessibilityActionResultAndClear(int interactionId) {
         synchronized (mInstanceLock) {
             final boolean success = waitForResultTimedLocked(interactionId);
             final boolean result = success ? mPerformAccessibilityActionResult : false;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6939c2c..d7d6792 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -380,8 +380,8 @@
             return Collections.emptyList();
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
-        return client.findAccessibilityNodeInfosByText(mConnectionId, text, mWindowId,
-                mSourceNodeId);
+        return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
+                text);
     }
 
     /**
@@ -903,6 +903,17 @@
     }
 
     /**
+     * Gets the id of the source node.
+     *
+     * @return The id.
+     *
+     * @hide
+     */
+    public long getSourceNodeId() {
+        return mSourceNodeId;
+    }
+
+    /**
      * Sets if this instance is sealed.
      *
      * @param sealed Whether is sealed.
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 07aeb9a..b60f50e 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -564,6 +564,17 @@
     }
 
     /**
+     * Gets the id of the source node.
+     *
+     * @return The id.
+     *
+     * @hide
+     */
+    public long getSourceNodeId() {
+        return mSourceNodeId;
+    }
+
+    /**
      * Sets the unique id of the IAccessibilityServiceConnection over which
      * this instance can send requests to the system.
      *
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index a90c427..ae6869c 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -31,13 +31,13 @@
         IAccessibilityInteractionConnectionCallback callback,
         int interrogatingPid, long interrogatingTid);
 
-    void findAccessibilityNodeInfoByViewId(int id, int interactionId,
+    void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int id, int interactionId,
         IAccessibilityInteractionConnectionCallback callback,
         int interrogatingPid, long interrogatingTid);
 
-    void findAccessibilityNodeInfosByText(String text, long accessibilityNodeId,
-        int interactionId, IAccessibilityInteractionConnectionCallback callback,
-        int interrogatingPid, long interrogatingTid);
+    void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId,
+        IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+        long interrogatingTid);
 
     void performAccessibilityAction(long accessibilityNodeId, int action, int interactionId,
         IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index c3794be..320c75d 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -49,5 +49,7 @@
 
     void removeAccessibilityInteractionConnection(IWindow windowToken);
 
-    void registerEventListener(IEventListener client);
+    void registerUiTestAutomationService(IEventListener listener, in AccessibilityServiceInfo info);
+
+    void unregisterUiTestAutomationService(IEventListener listener);
 }
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 5ec1ec3..bd02d62 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -193,10 +193,12 @@
     /**
      * The default implementation performs the deletion around the current
      * selection position of the editable text.
+     * @param beforeLength
+     * @param afterLength
      */
-    public boolean deleteSurroundingText(int leftLength, int rightLength) {
-        if (DEBUG) Log.v(TAG, "deleteSurroundingText " + leftLength
-                + " / " + rightLength);
+    public boolean deleteSurroundingText(int beforeLength, int afterLength) {
+        if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength
+                + " / " + afterLength);
         final Editable content = getEditable();
         if (content == null) return false;
 
@@ -226,17 +228,17 @@
 
         int deleted = 0;
 
-        if (leftLength > 0) {
-            int start = a - leftLength;
+        if (beforeLength > 0) {
+            int start = a - beforeLength;
             if (start < 0) start = 0;
             content.delete(start, a);
             deleted = a - start;
         }
 
-        if (rightLength > 0) {
+        if (afterLength > 0) {
             b = b - deleted;
 
-            int end = b + rightLength;
+            int end = b + afterLength;
             if (end > content.length()) end = content.length();
 
             content.delete(b, end);
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index a6639d1..3563d4d 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -138,19 +138,21 @@
             int flags);
 
     /**
-     * Delete <var>leftLength</var> characters of text before the current cursor
-     * position, and delete <var>rightLength</var> characters of text after the
-     * current cursor position, excluding composing text.
+     * Delete <var>beforeLength</var> characters of text before the current cursor
+     * position, and delete <var>afterLength</var> characters of text after the
+     * current cursor position, excluding composing text. Before and after refer
+     * to the order of the characters in the string, not to their visual representation.
      * 
-     * @param leftLength The number of characters to be deleted before the
+     *
+     * @param beforeLength The number of characters to be deleted before the
      *        current cursor position.
-     * @param rightLength The number of characters to be deleted after the
+     * @param afterLength The number of characters to be deleted after the
      *        current cursor position.
-     *        
+     *
      * @return Returns true on success, false if the input connection is no longer
      * valid.
      */
-    public boolean deleteSurroundingText(int leftLength, int rightLength);
+    public boolean deleteSurroundingText(int beforeLength, int afterLength);
 
     /**
      * Set composing text around the current cursor position with the given text,
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 690ea85..a48473e 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -62,8 +62,8 @@
         return mTarget.getExtractedText(request, flags);
     }
 
-    public boolean deleteSurroundingText(int leftLength, int rightLength) {
-        return mTarget.deleteSurroundingText(leftLength, rightLength);
+    public boolean deleteSurroundingText(int beforeLength, int afterLength) {
+        return mTarget.deleteSurroundingText(beforeLength, afterLength);
     }
 
     public boolean setComposingText(CharSequence text, int newCursorPosition) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index b41e6f5..7171b58 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -651,19 +651,7 @@
                 }
             }
             
-            if (mServedInputConnection != null) {
-                // We need to tell the previously served view that it is no
-                // longer the input target, so it can reset its state.  Schedule
-                // this call on its window's Handler so it will be on the correct
-                // thread and outside of our lock.
-                Handler vh = mServedView.getHandler();
-                if (vh != null) {
-                    // This will result in a call to reportFinishInputConnection()
-                    // below.
-                    vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION,
-                            mServedInputConnection));
-                }
-            }
+            notifyInputConnectionFinished();
             
             mServedView = null;
             mCompletions = null;
@@ -671,7 +659,25 @@
             clearConnectionLocked();
         }
     }
-    
+
+    /**
+     * Notifies the served view that the current InputConnection will no longer be used.
+     */
+    private void notifyInputConnectionFinished() {
+        if (mServedView != null && mServedInputConnection != null) {
+            // We need to tell the previously served view that it is no
+            // longer the input target, so it can reset its state.  Schedule
+            // this call on its window's Handler so it will be on the correct
+            // thread and outside of our lock.
+            Handler vh = mServedView.getHandler();
+            if (vh != null) {
+                // This will result in a call to reportFinishInputConnection() below.
+                vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION,
+                        mServedInputConnection));
+            }
+        }
+    }
+
     /**
      * Called from the FINISH_INPUT_CONNECTION message above.
      * @hide
@@ -681,7 +687,7 @@
             ic.finishComposingText();
         }
     }
-    
+
     public void displayCompletions(View view, CompletionInfo[] completions) {
         checkFocus();
         synchronized (mH) {
@@ -831,7 +837,7 @@
      * shown with {@link #SHOW_FORCED}.
      */
     public static final int HIDE_NOT_ALWAYS = 0x0002;
-    
+
     /**
      * Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}
      * without a result: request to hide the soft input window from the
@@ -993,7 +999,7 @@
         tba.fieldId = view.getId();
         InputConnection ic = view.onCreateInputConnection(tba);
         if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
-        
+
         synchronized (mH) {
             // Now that we are locked again, validate that our state hasn't
             // changed.
@@ -1012,6 +1018,8 @@
             // Hook 'em up and let 'er rip.
             mCurrentTextBoxAttribute = tba;
             mServedConnecting = false;
+            // Notify the served view that its previous input connection is finished
+            notifyInputConnectionFinished();
             mServedInputConnection = ic;
             IInputContext servedContext;
             if (ic != null) {
@@ -1115,7 +1123,7 @@
         }
     }
 
-    void scheduleCheckFocusLocked(View view) {
+    static void scheduleCheckFocusLocked(View view) {
         Handler vh = view.getHandler();
         if (vh != null && !vh.hasMessages(ViewRootImpl.CHECK_FOCUS)) {
             // This will result in a call to checkFocus() below.
@@ -1585,6 +1593,27 @@
     }
 
     /**
+     * Force switch to the next input method and subtype. If there is no IME enabled except
+     * current IME and subtype, do nothing.
+     * @param imeToken Supplies the identifying token given to an input method when it was started,
+     * which allows it to perform this operation on itself.
+     * @param onlyCurrentIme if true, the framework will find the next subtype which
+     * belongs to the current IME
+     * @return true if the current input method and subtype was successfully switched to the next
+     * input method and subtype.
+     */
+    public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
+        synchronized (mH) {
+            try {
+                return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId, e);
+                return false;
+            }
+        }
+    }
+
+    /**
      * Set additional input method subtypes. Only a process which shares the same uid with the IME
      * can add additional input method subtypes to the IME.
      * Please note that a subtype's status is stored in the system.
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index 30bbb04..ee9b949 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -169,7 +169,9 @@
             if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()))
                 return;
 
-            NetworkInfo info = (NetworkInfo)intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+            final ConnectivityManager connManager = (ConnectivityManager) context
+                    .getSystemService(Context.CONNECTIVITY_SERVICE);
+            final NetworkInfo info = connManager.getActiveNetworkInfo();
             if (info != null)
                 mRoaming = info.isRoaming();
         };
diff --git a/core/java/android/webkit/WebCoreThreadWatchdog.java b/core/java/android/webkit/WebCoreThreadWatchdog.java
index d100260..0541d5d 100644
--- a/core/java/android/webkit/WebCoreThreadWatchdog.java
+++ b/core/java/android/webkit/WebCoreThreadWatchdog.java
@@ -40,9 +40,6 @@
     // WebCore thread unresponsive.
     private static final int TIMED_OUT = 101;
 
-    // Message to tell the Watchdog thread to terminate.
-    private static final int QUIT = 102;
-
     // Wait 10s after hearing back from the WebCore thread before checking it's still alive.
     private static final int HEARTBEAT_PERIOD = 10 * 1000;
 
@@ -57,7 +54,6 @@
     private Handler mWebCoreThreadHandler;
     private Handler mHandler;
     private boolean mPaused;
-    private boolean mPendingQuit;
 
     private static WebCoreThreadWatchdog sInstance;
 
@@ -88,12 +84,6 @@
         }
     }
 
-    public synchronized static void quit() {
-        if (sInstance != null) {
-            sInstance.quitWatchdog();
-        }
-    }
-
     private void setContext(Context context) {
         mContext = context;
     }
@@ -103,19 +93,6 @@
         mWebCoreThreadHandler = webCoreThreadHandler;
     }
 
-    private void quitWatchdog() {
-        if (mHandler == null) {
-            // The thread hasn't started yet, so set a flag to stop it starting.
-            mPendingQuit = true;
-            return;
-        }
-        // Clear any pending messages, and then post a quit to the WatchDog handler.
-        mHandler.removeMessages(TIMED_OUT);
-        mHandler.removeMessages(IS_ALIVE);
-        mWebCoreThreadHandler.removeMessages(EventHub.HEARTBEAT);
-        mHandler.obtainMessage(QUIT).sendToTarget();
-    }
-
     private void pauseWatchdog() {
         mPaused = true;
 
@@ -146,12 +123,8 @@
         mHandler.sendMessageDelayed(mHandler.obtainMessage(TIMED_OUT), TIMEOUT_PERIOD);
     }
 
-    private boolean createHandler() {
+    private void createHandler() {
         synchronized (WebCoreThreadWatchdog.class) {
-            if (mPendingQuit) {
-                return false;
-            }
-
             mHandler = new Handler() {
                 @Override
                 public void handleMessage(Message msg) {
@@ -206,15 +179,9 @@
                             .setIcon(android.R.drawable.ic_dialog_alert)
                             .show();
                         break;
-
-                    case QUIT:
-                        Looper.myLooper().quit();
-                        break;
                     }
                 }
             };
-
-            return true;
         }
     }
 
@@ -222,9 +189,7 @@
     public void run() {
         Looper.prepare();
 
-        if (!createHandler()) {
-            return;
-        }
+        createHandler();
 
         // Send the initial control to WebViewCore and start the timeout timer as long as we aren't
         // paused.
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index b4c38db..c463b40 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1156,8 +1156,13 @@
     }
 
     /**
-     * Tell the WebView to load image resources automatically.
-     * @param flag True if the WebView should load images automatically.
+     * Sets whether the WebView should load image resources. Note that this method
+     * controls loading of all images, including those embedded using the data
+     * URI scheme. Use {@link #setBlockNetworkImage} to control loading only
+     * of images specified using network URI schemes. Note that if the value of this
+     * setting is changed from false to true, all images resources referenced
+     * by content currently displayed by the WebView are loaded automatically.
+     * @param flag Whether the WebView should load image resources.
      */
     public synchronized void setLoadsImagesAutomatically(boolean flag) {
         if (mLoadsImagesAutomatically != flag) {
@@ -1167,20 +1172,26 @@
     }
 
     /**
-     * Return true if the WebView will load image resources automatically.
-     * The default is true.
-     * @return True if the WebView loads images automatically.
+     * Returns true if the WebView loads image resources. This includes
+     * images embedded using the data URI scheme. The default is true.
+     * @return True if the WebView loads image resources.
      */
     public synchronized boolean getLoadsImagesAutomatically() {
         return mLoadsImagesAutomatically;
     }
 
     /**
-     * Tell the WebView to block network images. This is only checked when
-     * {@link #getLoadsImagesAutomatically} is true. If you set the value to
-     * false, images will automatically be loaded. Use this api to reduce
-     * bandwidth only. Use {@link #setBlockNetworkLoads} if possible.
-     * @param flag True if the WebView should block network images.
+     * Sets whether the WebView should not load image resources from the
+     * network (resources accessed via http and https URI schemes).  Note
+     * that this method has no effect unless
+     * {@link #getLoadsImagesAutomatically} returns true. Also note that
+     * disabling all network loads using {@link #setBlockNetworkLoads}
+     * will also prevent network images from loading, even if this flag is set
+     * to false. When the value of this setting is changed from true to false,
+     * network images resources referenced by content currently displayed by
+     * the WebView are fetched automatically.
+     * @param flag Whether the WebView should not load image resources from
+     * the network.
      * @see #setBlockNetworkLoads
      */
     public synchronized void setBlockNetworkImage(boolean flag) {
@@ -1191,20 +1202,27 @@
     }
 
     /**
-     * Return true if the WebView will block network images. The default is
-     * false.
-     * @return True if the WebView blocks network images.
+     * Returns true if the WebView does not load image resources from the network.
+     * The default is false.
+     * @return True if the WebView does not load image resources from the network.
      */
     public synchronized boolean getBlockNetworkImage() {
         return mBlockNetworkImage;
     }
 
     /**
-     * Tell the WebView to block all network load requests. If you set the
-     * value to false, you must call {@link android.webkit.WebView#reload} to
-     * fetch remote resources. This flag supercedes the value passed to
-     * {@link #setBlockNetworkImage}.
-     * @param flag True if the WebView should block all network loads.
+     * Sets whether the WebView should not load resources from the network.
+     * Use {@link #setBlockNetworkImage} to only avoid loading
+     * image resources. Note that if the value of this setting is
+     * changed from true to false, network resources referenced by content
+     * currently displayed by the WebView are not fetched until
+     * {@link android.webkit.WebView#reload} is called.
+     * If the application does not have the
+     * {@link android.Manifest.permission#INTERNET} permission, attempts to set
+     * a value of false will cause a {@link java.lang.SecurityException}
+     * to be thrown.
+     * @param flag Whether the WebView should not load any resources
+     * from the network.
      * @see android.webkit.WebView#reload
      */
     public synchronized void setBlockNetworkLoads(boolean flag) {
@@ -1216,9 +1234,11 @@
     }
 
     /**
-     * Return true if the WebView will block all network loads. The default is
-     * false.
-     * @return True if the WebView blocks all network loads.
+     * Returns true if the WebView does not load any resources from the network.
+     * The default value is false if the application has the
+     * {@link android.Manifest.permission#INTERNET} permission, otherwise it is
+     * true.
+     * @return True if the WebView does not load any resources from the network.
      */
     public synchronized boolean getBlockNetworkLoads() {
         return mBlockNetworkLoads;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 148be5c..b173de0 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -60,6 +60,10 @@
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.speech.tts.TextToSpeech;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.Selection;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
@@ -125,12 +129,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-
-import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY;
-
 /**
  * <p>A View that displays web pages. This class is the basis upon which you
  * can roll your own web browser or simply display some online content within your Activity.
@@ -363,39 +361,167 @@
     }
 
     /**
-     * InputConnection used for ContentEditable. This captures the 'delete'
-     * commands and sends delete key presses.
+     * InputConnection used for ContentEditable. This captures changes
+     * to the text and sends them either as key strokes or text changes.
      */
     private class WebViewInputConnection extends BaseInputConnection {
+        // Used for mapping characters to keys typed.
+        private KeyCharacterMap mKeyCharacterMap;
+        private boolean mIsKeySentByMe;
+
         public WebViewInputConnection() {
-            super(WebView.this, false);
+            super(WebView.this, true);
         }
 
-        private void sendKeyPress(int keyCode) {
-            long eventTime = SystemClock.uptimeMillis();
-            sendKeyEvent(new KeyEvent(eventTime, eventTime,
-                    KeyEvent.ACTION_DOWN, keyCode, 0, 0,
-                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
-                    KeyEvent.FLAG_SOFT_KEYBOARD));
-            sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
-                    KeyEvent.ACTION_UP, keyCode, 0, 0,
-                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
-                    KeyEvent.FLAG_SOFT_KEYBOARD));
+        @Override
+        public boolean sendKeyEvent(KeyEvent event) {
+            // Latin IME occasionally sends delete codes directly using
+            // sendKeyEvents. WebViewInputConnection should treat this
+            // as a deleteSurroundingText.
+            if (!mIsKeySentByMe
+                    && event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
+                Editable editable = getEditable();
+                int selectionStart = Selection.getSelectionStart(editable);
+                int selectionEnd = Selection.getSelectionEnd(editable);
+                if (selectionEnd > 0 && (selectionStart == selectionEnd)) {
+                    int action = event.getAction();
+                    if (action == KeyEvent.ACTION_UP) {
+                        return deleteSurroundingText(1, 0);
+                    } else if (action == KeyEvent.ACTION_DOWN) {
+                        return true; // the delete will happen in ACTION_UP
+                    }
+                }
+            }
+            return super.sendKeyEvent(event);
+        }
+
+        public void setTextAndKeepSelection(CharSequence text) {
+            Editable editable = getEditable();
+            int selectionStart = Selection.getSelectionStart(editable);
+            int selectionEnd = Selection.getSelectionEnd(editable);
+            editable.replace(0, editable.length(), text);
+            InputMethodManager imm = InputMethodManager.peekInstance();
+            if (imm != null) {
+                // Since the text has changed, do not allow the IME to replace the
+                // existing text as though it were a completion.
+                imm.restartInput(WebView.this);
+            }
+            // Keep the previous selection.
+            selectionStart = Math.min(selectionStart, editable.length());
+            selectionEnd = Math.min(selectionEnd, editable.length());
+            setSelection(selectionStart, selectionEnd);
+        }
+
+        @Override
+        public boolean setComposingText(CharSequence text, int newCursorPosition) {
+            Editable editable = getEditable();
+            int start = getComposingSpanStart(editable);
+            int end = getComposingSpanEnd(editable);
+            if (start < 0 || end < 0) {
+                start = Selection.getSelectionStart(editable);
+                end = Selection.getSelectionEnd(editable);
+            }
+            if (end < start) {
+                int temp = end;
+                end = start;
+                start = temp;
+            }
+            setNewText(start, end, text);
+            return super.setComposingText(text, newCursorPosition);
+        }
+
+        @Override
+        public boolean commitText(CharSequence text, int newCursorPosition) {
+            setComposingText(text, newCursorPosition);
+            int cursorPosition = Selection.getSelectionEnd(getEditable());
+            setComposingRegion(cursorPosition, cursorPosition);
+            return true;
         }
 
         @Override
         public boolean deleteSurroundingText(int leftLength, int rightLength) {
-            // Look for one-character delete and send it as a key press.
-            if (leftLength == 1 && rightLength == 0) {
-                sendKeyPress(KeyEvent.KEYCODE_DEL);
-            } else if (leftLength == 0 && rightLength == 1){
-                sendKeyPress(KeyEvent.KEYCODE_FORWARD_DEL);
-            } else if (mWebViewCore != null) {
-                mWebViewCore.sendMessage(EventHub.DELETE_SURROUNDING_TEXT,
-                        leftLength, rightLength);
-            }
+            Editable editable = getEditable();
+            int cursorPosition = Selection.getSelectionEnd(editable);
+            int startDelete = Math.max(0, cursorPosition - leftLength);
+            int endDelete = Math.min(editable.length(),
+                    cursorPosition + rightLength);
+            setNewText(startDelete, endDelete, "");
             return super.deleteSurroundingText(leftLength, rightLength);
         }
+
+        /**
+         * Sends a text change to webkit indirectly. If it is a single-
+         * character add or delete, it sends it as a key stroke. If it cannot
+         * be represented as a key stroke, it sends it as a field change.
+         * @param start The start offset (inclusive) of the text being changed.
+         * @param end The end offset (exclusive) of the text being changed.
+         * @param text The new text to replace the changed text.
+         */
+        private void setNewText(int start, int end, CharSequence text) {
+            mIsKeySentByMe = true;
+            Editable editable = getEditable();
+            CharSequence original = editable.subSequence(start, end);
+            boolean isCharacterAdd = false;
+            boolean isCharacterDelete = false;
+            int textLength = text.length();
+            int originalLength = original.length();
+            if (textLength > originalLength) {
+                isCharacterAdd = (textLength == originalLength + 1)
+                        && TextUtils.regionMatches(text, 0, original, 0,
+                                originalLength);
+            } else if (originalLength > textLength) {
+                isCharacterDelete = (textLength == originalLength - 1)
+                        && TextUtils.regionMatches(text, 0, original, 0,
+                                textLength);
+            }
+            if (isCharacterAdd) {
+                sendCharacter(text.charAt(textLength - 1));
+            } else if (isCharacterDelete) {
+                sendDeleteKey();
+            } else if (textLength != originalLength ||
+                    !TextUtils.regionMatches(text, 0, original, 0,
+                            textLength)) {
+                // Send a message so that key strokes and text replacement
+                // do not come out of order.
+                Message replaceMessage = mPrivateHandler.obtainMessage(
+                        REPLACE_TEXT, start,  end, text.toString());
+                mPrivateHandler.sendMessage(replaceMessage);
+            }
+            mIsKeySentByMe = false;
+        }
+
+        /**
+         * Send a single character to the WebView as a key down and up event.
+         * @param c The character to be sent.
+         */
+        private void sendCharacter(char c) {
+            if (mKeyCharacterMap == null) {
+                mKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+            }
+            char[] chars = new char[1];
+            chars[0] = c;
+            KeyEvent[] events = mKeyCharacterMap.getEvents(chars);
+            if (events != null) {
+                for (KeyEvent event : events) {
+                    sendKeyEvent(event);
+                }
+            }
+        }
+
+        /**
+         * Send the delete character as a key down and up event.
+         */
+        private void sendDeleteKey() {
+            long eventTime = SystemClock.uptimeMillis();
+            sendKeyEvent(new KeyEvent(eventTime, eventTime,
+                    KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0, 0,
+                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+                    KeyEvent.FLAG_SOFT_KEYBOARD));
+            sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
+                    KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL, 0, 0,
+                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+                    KeyEvent.FLAG_SOFT_KEYBOARD));
+        }
     }
 
 
@@ -424,7 +550,7 @@
     private final RectF mVisibleContentRect = new RectF();
     private boolean mGLViewportEmpty = false;
     WebViewInputConnection mInputConnection = null;
-
+    private int mFieldPointer;
 
     /**
      *  Transportation object for returning WebView across thread boundaries.
@@ -704,14 +830,21 @@
     // know to handle Shift and arrows natively first
     private boolean mAccessibilityScriptInjected;
 
-    static final boolean USE_JAVA_TEXT_SELECTION = true;
-    static final boolean DEBUG_TEXT_HANDLES = false;
-    private Region mTextSelectionRegion = new Region();
-    private Paint mTextSelectionPaint;
     private Drawable mSelectHandleLeft;
     private Drawable mSelectHandleRight;
+    private Rect mSelectCursorBase = new Rect();
+    private int mSelectCursorBaseLayerId;
+    private Rect mSelectCursorExtent = new Rect();
+    private int mSelectCursorExtentLayerId;
+    private Rect mSelectDraggingCursor;
+    private Point mSelectDraggingOffset = new Point();
+    static final int HANDLE_ID_START = 0;
+    static final int HANDLE_ID_END = 1;
+    static final int HANDLE_ID_BASE = 2;
+    static final int HANDLE_ID_EXTENT = 3;
 
     static boolean sDisableNavcache = false;
+    static boolean sEnableWebTextView = false;
     // the color used to highlight the touch rectangles
     static final int HIGHLIGHT_COLOR = 0x6633b5e5;
     // the region indicating where the user touched on the screen
@@ -799,6 +932,8 @@
     static final int EXIT_FULLSCREEN_VIDEO              = 140;
 
     static final int COPY_TO_CLIPBOARD                  = 141;
+    static final int INIT_EDIT_FIELD                    = 142;
+    static final int REPLACE_TEXT                       = 143;
 
     private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
     private static final int LAST_PACKAGE_MSG_ID = HIT_TEST_RESULT;
@@ -976,9 +1111,6 @@
     private Rect mScrollingLayerBounds = new Rect();
     private boolean mSentAutoScrollMessage = false;
 
-    // Temporary hack to work around the context removal upon memory pressure
-    private static boolean mIncrementEGLContextHack = false;
-
     // used for serializing asynchronously handled touch events.
     private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
 
@@ -1334,7 +1466,6 @@
     private void init() {
         OnTrimMemoryListener.init(getContext());
         sDisableNavcache = nativeDisableNavcache();
-
         setWillNotDraw(false);
         setFocusable(true);
         setFocusableInTouchMode(true);
@@ -2523,7 +2654,7 @@
         checkThread();
         mContentWidth = 0;
         mContentHeight = 0;
-        setBaseLayer(0, null, false, false, false);
+        setBaseLayer(0, null, false, false);
         mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT);
     }
 
@@ -2572,12 +2703,6 @@
         return mZoomManager.getScale();
     }
 
-    // Called by JNI. Returns the scale to apply to the text selection handles
-    /* package */ float getTextHandleScale() {
-        float density = mContext.getResources().getDisplayMetrics().density;
-        return density / getScale();
-    }
-
     /**
      * Compute the reading level scale of the WebView
      * @param scale The current scale.
@@ -2697,6 +2822,34 @@
         return result;
     }
 
+    int getBlockLeftEdge(int x, int y, float readingScale) {
+        if (!sDisableNavcache) {
+            return nativeGetBlockLeftEdge(x, y, readingScale);
+        }
+
+        float invReadingScale = 1.0f / readingScale;
+        int readingWidth = (int) (getViewWidth() * invReadingScale);
+        int left = NO_LEFTEDGE;
+        if (mFocusedNode != null) {
+            final int length = mFocusedNode.mEnclosingParentRects.length;
+            for (int i = 0; i < length; i++) {
+                Rect rect = mFocusedNode.mEnclosingParentRects[i];
+                if (rect.width() < mFocusedNode.mHitTestSlop) {
+                    // ignore bounding boxes that are too small
+                    continue;
+                } else if (left != NO_LEFTEDGE && rect.width() > readingWidth) {
+                    // stop when bounding box doesn't fit the screen width
+                    // at reading scale
+                    break;
+                }
+
+                left = rect.left;
+            }
+        }
+
+        return left;
+    }
+
     // Called by JNI when the DOM has changed the focus.  Clear the focus so
     // that new keys will go to the newly focused field
     private void domChangedFocus() {
@@ -3768,6 +3921,16 @@
         if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) {
             return;
         }
+        if (mSelectingText) {
+            int dx = mScrollingLayerRect.left - x;
+            int dy = mScrollingLayerRect.top - y;
+            if (mSelectCursorBaseLayerId == mCurrentScrollingLayerId) {
+                mSelectCursorBase.offset(dx, dy);
+            }
+            if (mSelectCursorExtentLayerId == mCurrentScrollingLayerId) {
+                mSelectCursorExtent.offset(dx, dy);
+            }
+        }
         nativeScrollLayer(mCurrentScrollingLayerId, x, y);
         mScrollingLayerRect.left = x;
         mScrollingLayerRect.top = y;
@@ -4385,14 +4548,9 @@
         }
 
         if (canvas.isHardwareAccelerated()) {
-            if (mIncrementEGLContextHack == false) {
-                mIncrementEGLContextHack = true;
-                EGL10 egl = (EGL10) EGLContext.getEGL();
-                EGLDisplay eglDisplay = egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
-                int[] version = new int[2];
-                egl.eglInitialize(eglDisplay, version);
-            }
             mZoomManager.setHardwareAccelerated();
+        } else {
+            mWebViewCore.resumeWebKitDraw();
         }
 
         int saveCount = canvas.save();
@@ -4547,12 +4705,7 @@
      * Select the word at the indicated content coordinates.
      */
     boolean selectText(int x, int y) {
-        if (!setUpSelect(true, x, y)) {
-            return false;
-        }
-        nativeSetExtendSelection();
-        mDrawSelectionPointer = false;
-        mTouchMode = TOUCH_DRAG_MODE;
+        mWebViewCore.sendMessage(EventHub.SELECT_WORD_AT, x, y);
         return true;
     }
 
@@ -4640,11 +4793,19 @@
     }
 
     void setBaseLayer(int layer, Region invalRegion, boolean showVisualIndicator,
-            boolean isPictureAfterFirstLayout, boolean registerPageSwapCallback) {
+            boolean isPictureAfterFirstLayout) {
         if (mNativeClass == 0)
             return;
-        nativeSetBaseLayer(mNativeClass, layer, invalRegion, showVisualIndicator,
-                isPictureAfterFirstLayout, registerPageSwapCallback);
+        boolean queueFull;
+        queueFull = nativeSetBaseLayer(mNativeClass, layer, invalRegion,
+                                       showVisualIndicator, isPictureAfterFirstLayout);
+
+        if (layer == 0 || isPictureAfterFirstLayout) {
+            mWebViewCore.resumeWebKitDraw();
+        } else if (queueFull) {
+            mWebViewCore.pauseWebKitDraw();
+        }
+
         if (mHTML5VideoViewProxy != null) {
             mHTML5VideoViewProxy.setBaseLayer(layer);
         }
@@ -4753,11 +4914,8 @@
         int extras = DRAW_EXTRAS_NONE;
         if (mFindIsUp) {
             extras = DRAW_EXTRAS_FIND;
-        } else if (mSelectingText && (!USE_JAVA_TEXT_SELECTION || DEBUG_TEXT_HANDLES)) {
+        } else if (mSelectingText) {
             extras = DRAW_EXTRAS_SELECTION;
-            nativeSetSelectionPointer(mNativeClass,
-                    mDrawSelectionPointer,
-                    mZoomManager.getInvScale(), mSelectX, mSelectY - getTitleHeight());
         } else if (drawCursorRing) {
             extras = DRAW_EXTRAS_CURSOR_RING;
         }
@@ -4802,7 +4960,7 @@
         }
 
         canvas.restoreToCount(saveCount);
-        if (mSelectingText && USE_JAVA_TEXT_SELECTION) {
+        if (mSelectingText) {
             drawTextSelectionHandles(canvas);
         }
 
@@ -4824,30 +4982,12 @@
     }
 
     private void drawTextSelectionHandles(Canvas canvas) {
-        if (mTextSelectionPaint == null) {
-            mTextSelectionPaint = new Paint();
-            mTextSelectionPaint.setColor(HIGHLIGHT_COLOR);
-        }
-        mTextSelectionRegion.setEmpty();
-        nativeGetTextSelectionRegion(mNativeClass, mTextSelectionRegion);
-        Rect r = new Rect();
-        RegionIterator iter = new RegionIterator(mTextSelectionRegion);
-        Rect clip = canvas.getClipBounds();
-        while (iter.next(r)) {
-            r.set(contentToViewDimension(r.left),
-                    contentToViewDimension(r.top),
-                    contentToViewDimension(r.right),
-                    contentToViewDimension(r.bottom));
-            if (r.intersect(clip)) {
-                canvas.drawRect(r, mTextSelectionPaint);
-            }
-        }
         if (mSelectHandleLeft == null) {
             mSelectHandleLeft = mContext.getResources().getDrawable(
                     com.android.internal.R.drawable.text_select_handle_left);
         }
         int[] handles = new int[4];
-        nativeGetSelectionHandles(mNativeClass, handles);
+        getSelectionHandles(handles);
         int start_x = contentToViewDimension(handles[0]);
         int start_y = contentToViewDimension(handles[1]);
         int end_x = contentToViewDimension(handles[2]);
@@ -4865,14 +5005,31 @@
         mSelectHandleRight.setBounds(end_x, end_y,
                 end_x + mSelectHandleRight.getIntrinsicWidth(),
                 end_y + mSelectHandleRight.getIntrinsicHeight());
-        if (DEBUG_TEXT_HANDLES) {
-            mSelectHandleLeft.setAlpha(125);
-            mSelectHandleRight.setAlpha(125);
-        }
         mSelectHandleLeft.draw(canvas);
         mSelectHandleRight.draw(canvas);
     }
 
+    /**
+     * Takes an int[4] array as an output param with the values being
+     * startX, startY, endX, endY
+     */
+    private void getSelectionHandles(int[] handles) {
+        handles[0] = mSelectCursorBase.right;
+        handles[1] = mSelectCursorBase.bottom -
+                (mSelectCursorBase.height() / 4);
+        handles[2] = mSelectCursorExtent.left;
+        handles[3] = mSelectCursorExtent.bottom
+                - (mSelectCursorExtent.height() / 4);
+        if (!nativeIsBaseFirst(mNativeClass)) {
+            int swap = handles[0];
+            handles[0] = handles[2];
+            handles[2] = swap;
+            swap = handles[1];
+            handles[1] = handles[3];
+            handles[3] = swap;
+        }
+    }
+
     // draw history
     private boolean mDrawHistory = false;
     private Picture mHistoryPicture = null;
@@ -4932,7 +5089,7 @@
     /* package */ void deleteSelection(int start, int end) {
         mTextGeneration++;
         WebViewCore.TextSelectionData data
-                = new WebViewCore.TextSelectionData(start, end);
+                = new WebViewCore.TextSelectionData(start, end, 0);
         mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0,
                 data);
     }
@@ -4951,12 +5108,18 @@
 
     @Override
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
-        outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN
+        outAttrs.inputType = EditorInfo.IME_FLAG_NO_FULLSCREEN
                 | EditorInfo.TYPE_CLASS_TEXT
-                | EditorInfo.TYPE_TEXT_VARIATION_NORMAL;
+                | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
+                | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
+                | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT
+                | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES;
+        outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE;
+
         if (mInputConnection == null) {
             mInputConnection = new WebViewInputConnection();
         }
+        outAttrs.initialCapsMode = mInputConnection.getCursorCapsMode(InputType.TYPE_CLASS_TEXT);
         return mInputConnection;
     }
 
@@ -5007,6 +5170,9 @@
      * multiline, and what text it contains.  It also removes it if necessary.
      */
     /* package */ void rebuildWebTextView() {
+        if (!sEnableWebTextView) {
+            return; // always use WebKit's text entry
+        }
         // If the WebView does not have focus, do nothing until it gains focus.
         if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())) {
             return;
@@ -5379,15 +5545,6 @@
                         return pinScrollTo(mContentWidth, mScrollY, true, 0);
                 }
             }
-            if (mSelectingText) {
-                int xRate = keyCode == KeyEvent.KEYCODE_DPAD_LEFT
-                    ? -1 : keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ? 1 : 0;
-                int yRate = keyCode == KeyEvent.KEYCODE_DPAD_UP ?
-                    -1 : keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : 0;
-                int multiplier = event.getRepeatCount() + 1;
-                moveSelection(xRate * multiplier, yRate * multiplier);
-                return true;
-            }
             if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
                 playSoundEffect(keyCodeToSoundsEffect(keyCode));
                 return true;
@@ -5540,14 +5697,8 @@
             mGotCenterDown = false;
 
             if (mSelectingText) {
-                if (mExtendSelection) {
-                    copySelection();
-                    selectionDone();
-                } else {
-                    mExtendSelection = true;
-                    nativeSetExtendSelection();
-                    invalidate(); // draw the i-beam instead of the arrow
-                }
+                copySelection();
+                selectionDone();
                 return true; // discard press if copy in progress
             }
 
@@ -5593,21 +5744,7 @@
         return false;
     }
 
-    /*
-     * Enter selecting text mode, and see if CAB should be shown.
-     * Returns true if the WebView is now in
-     * selecting text mode (including if it was already in that mode, and this
-     * method did nothing).
-     */
-    private boolean setUpSelect(boolean selectWord, int x, int y) {
-        if (0 == mNativeClass) return false; // client isn't initialized
-        if (inFullScreenMode()) return false;
-        if (mSelectingText) return true;
-        nativeResetSelection();
-        if (selectWord && !nativeWordSelection(x, y)) {
-            selectionDone();
-            return false;
-        }
+    private boolean startSelectActionMode() {
         mSelectCallback = new SelectActionModeCallback();
         mSelectCallback.setWebView(this);
         if (startActionMode(mSelectCallback) == null) {
@@ -5616,54 +5753,43 @@
             selectionDone();
             return false;
         }
-        mExtendSelection = false;
-        mSelectingText = mDrawSelectionPointer = true;
-        if (DEBUG_TEXT_HANDLES) {
-            // Debugging text handles requires running in software mode
-            setLayerType(LAYER_TYPE_SOFTWARE, null);
-        }
-        // don't let the picture change during text selection
-        WebViewCore.pauseUpdatePicture(mWebViewCore);
-        if (nativeHasCursorNode()) {
-            Rect rect = nativeCursorNodeBounds();
-            mSelectX = contentToViewX(rect.left);
-            mSelectY = contentToViewY(rect.top);
-        } else if (mLastTouchY > getVisibleTitleHeightImpl()) {
-            mSelectX = mScrollX + mLastTouchX;
-            mSelectY = mScrollY + mLastTouchY;
-        } else {
-            mSelectX = mScrollX + getViewWidth() / 2;
-            mSelectY = mScrollY + getViewHeightWithTitle() / 2;
-        }
-        nativeHideCursor();
-        mMinAutoScrollX = 0;
-        mMaxAutoScrollX = getViewWidth();
-        mMinAutoScrollY = 0;
-        mMaxAutoScrollY = getViewHeightWithTitle();
-        mCurrentScrollingLayerId = nativeScrollableLayer(viewToContentX(mSelectX),
-                viewToContentY(mSelectY), mScrollingLayerRect,
-                mScrollingLayerBounds);
-        if (mCurrentScrollingLayerId != 0) {
-            if (mScrollingLayerRect.left != mScrollingLayerRect.right) {
-                mMinAutoScrollX = Math.max(mMinAutoScrollX,
-                        contentToViewX(mScrollingLayerBounds.left));
-                mMaxAutoScrollX = Math.min(mMaxAutoScrollX,
-                        contentToViewX(mScrollingLayerBounds.right));
-            }
-            if (mScrollingLayerRect.top != mScrollingLayerRect.bottom) {
-                mMinAutoScrollY = Math.max(mMinAutoScrollY,
-                        contentToViewY(mScrollingLayerBounds.top));
-                mMaxAutoScrollY = Math.min(mMaxAutoScrollY,
-                        contentToViewY(mScrollingLayerBounds.bottom));
-            }
-        }
-        mMinAutoScrollX += SELECT_SCROLL;
-        mMaxAutoScrollX -= SELECT_SCROLL;
-        mMinAutoScrollY += SELECT_SCROLL;
-        mMaxAutoScrollY -= SELECT_SCROLL;
+        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         return true;
     }
 
+    private void syncSelectionCursors() {
+        mSelectCursorBaseLayerId =
+                nativeGetHandleLayerId(mNativeClass, HANDLE_ID_BASE, mSelectCursorBase);
+        mSelectCursorExtentLayerId =
+                nativeGetHandleLayerId(mNativeClass, HANDLE_ID_EXTENT, mSelectCursorExtent);
+    }
+
+    private boolean setupWebkitSelect() {
+        syncSelectionCursors();
+        if (!startSelectActionMode()) {
+            selectionDone();
+            return false;
+        }
+        mSelectingText = true;
+        mTouchMode = TOUCH_DRAG_MODE;
+        return true;
+    }
+
+    private void updateWebkitSelection() {
+        int[] handles = null;
+        if (mSelectingText) {
+            handles = new int[4];
+            handles[0] = mSelectCursorBase.centerX();
+            handles[1] = mSelectCursorBase.centerY();
+            handles[2] = mSelectCursorExtent.centerX();
+            handles[3] = mSelectCursorExtent.centerY();
+        } else {
+            nativeSetTextSelection(mNativeClass, 0);
+        }
+        mWebViewCore.removeMessages(EventHub.SELECT_TEXT);
+        mWebViewCore.sendMessageAtFrontOfQueue(EventHub.SELECT_TEXT, handles);
+    }
+
     /**
      * Use this method to put the WebView into text selection mode.
      * Do not rely on this functionality; it will be deprecated in the future.
@@ -5672,7 +5798,6 @@
     @Deprecated
     public void emulateShiftHeld() {
         checkThread();
-        setUpSelect(false, 0, 0);
     }
 
     /**
@@ -5681,17 +5806,7 @@
      * @hide This is an implementation detail.
      */
     public void selectAll() {
-        if (0 == mNativeClass) return; // client isn't initialized
-        if (inFullScreenMode()) return;
-        if (!mSelectingText) {
-            // retrieve a point somewhere within the text
-            Point select = nativeSelectableText();
-            if (!selectText(select.x, select.y)) return;
-        }
-        nativeSelectAll();
-        mDrawSelectionPointer = false;
-        mExtendSelection = true;
-        invalidate();
+        mWebViewCore.sendMessage(EventHub.SELECT_ALL);
     }
 
     /**
@@ -5700,17 +5815,11 @@
     void selectionDone() {
         if (mSelectingText) {
             mSelectingText = false;
-            if (DEBUG_TEXT_HANDLES) {
-                // Debugging text handles required running in software mode, set
-                // back to default now
-                setLayerType(LAYER_TYPE_NONE, null);
-            }
             // finish is idempotent, so this is fine even if selectionDone was
             // called by mSelectCallback.onDestroyActionMode
             mSelectCallback.finish();
             mSelectCallback = null;
-            WebViewCore.resumePriority();
-            WebViewCore.resumeUpdatePicture(mWebViewCore);
+            updateWebkitSelection();
             invalidate(); // redraw without selection
             mAutoScrollX = 0;
             mAutoScrollY = 0;
@@ -5738,7 +5847,7 @@
                     .getSystemService(Context.CLIPBOARD_SERVICE);
             cm.setText(selection);
             int[] handles = new int[4];
-            nativeGetSelectionHandles(mNativeClass, handles);
+            getSelectionHandles(handles);
             mWebViewCore.sendMessage(EventHub.COPY_TEXT, handles);
         }
         invalidate(); // remove selection region and pointer
@@ -5753,7 +5862,7 @@
     public void cutSelection() {
         copySelection();
         int[] handles = new int[4];
-        nativeGetSelectionHandles(mNativeClass, handles);
+        getSelectionHandles(handles);
         mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles);
     }
 
@@ -5771,7 +5880,7 @@
             CharSequence pasteText = clipItem.getText();
             if (pasteText != null) {
                 int[] handles = new int[4];
-                nativeGetSelectionHandles(mNativeClass, handles);
+                getSelectionHandles(handles);
                 mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles);
                 mWebViewCore.sendMessage(EventHub.INSERT_TEXT,
                         pasteText.toString());
@@ -6002,7 +6111,7 @@
         calcOurContentVisibleRectF(mVisibleContentRect);
         nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
                 mGLViewportEmpty ? null : mViewRectViewport,
-                mVisibleContentRect);
+                mVisibleContentRect, getScale());
     }
 
     /**
@@ -6323,13 +6432,28 @@
                         EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION,
                                 (eventTime - mLastTouchUpTime), eventTime);
                     }
-                    if (mSelectingText) {
-                        mDrawSelectionPointer = false;
-                        mSelectionStarted = nativeStartSelection(contentX, contentY);
+                    mSelectionStarted = false;
+                    if (mSelectingText && mSelectHandleLeft != null
+                            && mSelectHandleRight != null) {
+                        int shiftedY = y - getTitleHeight() + mScrollY;
+                        int shiftedX = x + mScrollX;
+                        if (mSelectHandleLeft.getBounds()
+                                .contains(shiftedX, shiftedY)) {
+                            mSelectionStarted = true;
+                            mSelectDraggingCursor = mSelectCursorBase;
+                        } else if (mSelectHandleRight.getBounds()
+                                .contains(shiftedX, shiftedY)) {
+                            mSelectionStarted = true;
+                            mSelectDraggingCursor = mSelectCursorExtent;
+                        }
+                        if (mSelectDraggingCursor != null) {
+                            mSelectDraggingOffset.set(
+                                    mSelectDraggingCursor.left - contentX,
+                                    mSelectDraggingCursor.top - contentY);
+                        }
                         if (DebugFlags.WEB_VIEW) {
                             Log.v(LOGTAG, "select=" + contentX + "," + contentY);
                         }
-                        invalidate();
                     }
                 }
                 // Trigger the link
@@ -6395,6 +6519,26 @@
                         removeTouchHighlight();
                     }
                 }
+                if (mSelectingText && mSelectionStarted) {
+                    if (DebugFlags.WEB_VIEW) {
+                        Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
+                    }
+                    ViewParent parent = getParent();
+                    if (parent != null) {
+                        parent.requestDisallowInterceptTouchEvent(true);
+                    }
+                    if (deltaX != 0 || deltaY != 0) {
+                        mSelectDraggingCursor.offsetTo(
+                                contentX + mSelectDraggingOffset.x,
+                                contentY + mSelectDraggingOffset.y);
+                        updateWebkitSelection();
+                        mLastTouchX = x;
+                        mLastTouchY = y;
+                        invalidate();
+                    }
+                    break;
+                }
+
                 // pass the touch events from UI thread to WebCore thread
                 if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
                         || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
@@ -6437,30 +6581,6 @@
                 } else {
                     mVelocityTracker.addMovement(ev);
                 }
-                if (mSelectingText && mSelectionStarted) {
-                    if (DebugFlags.WEB_VIEW) {
-                        Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
-                    }
-                    ViewParent parent = getParent();
-                    if (parent != null) {
-                        parent.requestDisallowInterceptTouchEvent(true);
-                    }
-                    mAutoScrollX = x <= mMinAutoScrollX ? -SELECT_SCROLL
-                            : x >= mMaxAutoScrollX ? SELECT_SCROLL : 0;
-                    mAutoScrollY = y <= mMinAutoScrollY ? -SELECT_SCROLL
-                            : y >= mMaxAutoScrollY ? SELECT_SCROLL : 0;
-                    if ((mAutoScrollX != 0 || mAutoScrollY != 0)
-                            && !mSentAutoScrollMessage) {
-                        mSentAutoScrollMessage = true;
-                        mPrivateHandler.sendEmptyMessageDelayed(
-                                SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
-                    }
-                    if (deltaX != 0 || deltaY != 0) {
-                        nativeExtendSelection(contentX, contentY);
-                        invalidate();
-                    }
-                    break;
-                }
 
                 if (mTouchMode != TOUCH_DRAG_MODE &&
                         mTouchMode != TOUCH_DRAG_LAYER_MODE) {
@@ -6675,7 +6795,7 @@
                         } else {
                             if (mSelectingText) {
                                 // tapping on selection or controls does nothing
-                                if (!nativeHitSelection(contentX, contentY)) {
+                                if (!mSelectionStarted) {
                                     selectionDone();
                                 }
                                 break;
@@ -6972,6 +7092,12 @@
         if (mOverScrollGlow != null) {
             mOverScrollGlow.releaseAll();
         }
+
+        if (mSelectingText) {
+            mSelectionStarted = false;
+            syncSelectionCursors();
+            invalidate();
+        }
     }
 
     private void cancelTouch() {
@@ -7036,8 +7162,6 @@
     private int mTrackballYMove = 0;
     private boolean mSelectingText = false;
     private boolean mSelectionStarted = false;
-    private boolean mExtendSelection = false;
-    private boolean mDrawSelectionPointer = false;
     private static final int TRACKBALL_KEY_TIMEOUT = 1000;
     private static final int TRACKBALL_TIMEOUT = 200;
     private static final int TRACKBALL_WAIT = 100;
@@ -7106,14 +7230,8 @@
             mTrackballDown = false;
             mTrackballUpTime = time;
             if (mSelectingText) {
-                if (mExtendSelection) {
-                    copySelection();
-                    selectionDone();
-                } else {
-                    mExtendSelection = true;
-                    nativeSetExtendSelection();
-                    invalidate(); // draw the i-beam instead of the arrow
-                }
+                copySelection();
+                selectionDone();
                 return true; // discard press if copy in progress
             }
             if (DebugFlags.WEB_VIEW) {
@@ -7156,42 +7274,6 @@
         return true;
     }
 
-    void moveSelection(float xRate, float yRate) {
-        if (mNativeClass == 0)
-            return;
-        int width = getViewWidth();
-        int height = getViewHeight();
-        mSelectX += xRate;
-        mSelectY += yRate;
-        int maxX = width + mScrollX;
-        int maxY = height + mScrollY;
-        mSelectX = Math.min(maxX, Math.max(mScrollX - SELECT_CURSOR_OFFSET
-                , mSelectX));
-        mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
-                , mSelectY));
-        if (DebugFlags.WEB_VIEW) {
-            Log.v(LOGTAG, "moveSelection"
-                    + " mSelectX=" + mSelectX
-                    + " mSelectY=" + mSelectY
-                    + " mScrollX=" + mScrollX
-                    + " mScrollY=" + mScrollY
-                    + " xRate=" + xRate
-                    + " yRate=" + yRate
-                    );
-        }
-        nativeMoveSelection(viewToContentX(mSelectX), viewToContentY(mSelectY));
-        int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
-                : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
-                : 0;
-        int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
-                : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
-                : 0;
-        pinScrollBy(scrollX, scrollY, true, 0);
-        Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
-        requestRectangleOnScreen(select);
-        invalidate();
-   }
-
     private int scaleTrackballX(float xRate, int width) {
         int xMove = (int) (xRate / TRACKBALL_SCALE * width);
         int nextXMove = xMove;
@@ -7245,21 +7327,6 @@
         float yRate = mTrackballRemainsY * 1000 / elapsed;
         int viewWidth = getViewWidth();
         int viewHeight = getViewHeight();
-        if (mSelectingText) {
-            if (!mDrawSelectionPointer) {
-                // The last selection was made by touch, disabling drawing the
-                // selection pointer. Allow the trackball to adjust the
-                // position of the touch control.
-                mSelectX = contentToViewX(nativeSelectionX());
-                mSelectY = contentToViewY(nativeSelectionY());
-                mDrawSelectionPointer = mExtendSelection = true;
-                nativeSetExtendSelection();
-            }
-            moveSelection(scaleTrackballX(xRate, viewWidth),
-                    scaleTrackballY(yRate, viewHeight));
-            mTrackballRemainsX = mTrackballRemainsY = 0;
-            return;
-        }
         float ax = Math.abs(xRate);
         float ay = Math.abs(yRate);
         float maxA = Math.max(ax, ay);
@@ -8668,14 +8735,17 @@
                 case UPDATE_TEXTFIELD_TEXT_MSG_ID:
                     // Make sure that the textfield is currently focused
                     // and representing the same node as the pointer.
-                    if (inEditingMode() &&
-                            mWebTextView.isSameTextField(msg.arg1)) {
-                        if (msg.arg2 == mTextGeneration) {
-                            String text = (String) msg.obj;
-                            if (null == text) {
-                                text = "";
-                            }
+                    if (msg.arg2 == mTextGeneration) {
+                        String text = (String) msg.obj;
+                        if (null == text) {
+                            text = "";
+                        }
+                        if (inEditingMode() &&
+                                mWebTextView.isSameTextField(msg.arg1)) {
                             mWebTextView.setTextAndKeepSelection(text);
+                        } else if (mInputConnection != null &&
+                                mFieldPointer == msg.arg1) {
+                            mInputConnection.setTextAndKeepSelection(text);
                         }
                     }
                     break;
@@ -8963,6 +9033,24 @@
                     copyToClipboard((String) msg.obj);
                     break;
 
+                case INIT_EDIT_FIELD:
+                    if (mInputConnection != null) {
+                        mTextGeneration = 0;
+                        mFieldPointer = msg.arg1;
+                        mInputConnection.setTextAndKeepSelection((String) msg.obj);
+                    }
+                    break;
+
+                case REPLACE_TEXT:{
+                    String text = (String)msg.obj;
+                    int start = msg.arg1;
+                    int end = msg.arg2;
+                    int cursorPosition = start + text.length();
+                    replaceTextfieldText(start, end, text,
+                            cursorPosition, cursorPosition);
+                    break;
+                }
+
                 default:
                     super.handleMessage(msg);
                     break;
@@ -8999,6 +9087,7 @@
     /** @hide Called by JNI when pages are swapped (only occurs with hardware
      * acceleration) */
     protected void pageSwapCallback(boolean notifyAnimationStarted) {
+        mWebViewCore.resumeWebKitDraw();
         if (inEditingMode()) {
             didUpdateWebTextViewDimensions(ANYWHERE);
         }
@@ -9021,13 +9110,9 @@
         boolean isPictureAfterFirstLayout = viewState != null;
 
         if (updateBaseLayer) {
-            // Request a callback on pageSwap (to reposition the webtextview)
-            boolean registerPageSwapCallback =
-                !mZoomManager.isFixedLengthAnimationInProgress() && inEditingMode();
-
             setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
                     getSettings().getShowVisualIndicator(),
-                    isPictureAfterFirstLayout, registerPageSwapCallback);
+                    isPictureAfterFirstLayout);
         }
         final Point viewSize = draw.mViewSize;
         // We update the layout (i.e. request a layout from the
@@ -9088,11 +9173,26 @@
      */
     private void updateTextSelectionFromMessage(int nodePointer,
             int textGeneration, WebViewCore.TextSelectionData data) {
-        if (inEditingMode()
-                && mWebTextView.isSameTextField(nodePointer)
-                && textGeneration == mTextGeneration) {
-            mWebTextView.setSelectionFromWebKit(data.mStart, data.mEnd);
+        if (textGeneration == mTextGeneration) {
+            if (inEditingMode()
+                    && mWebTextView.isSameTextField(nodePointer)) {
+                mWebTextView.setSelectionFromWebKit(data.mStart, data.mEnd);
+            } else if (mInputConnection != null && mFieldPointer == nodePointer) {
+                mInputConnection.setSelection(data.mStart, data.mEnd);
+            }
         }
+
+        nativeSetTextSelection(mNativeClass, data.mSelectTextPtr);
+        if (data.mSelectTextPtr != 0) {
+            if (!mSelectingText) {
+                setupWebkitSelect();
+            } else if (!mSelectionStarted) {
+                syncSelectionCursors();
+            }
+        } else {
+            selectionDone();
+        }
+        invalidate();
     }
 
     // Class used to use a dropdown for a <select> element
@@ -9690,11 +9790,6 @@
         }
     }
 
-    /** @hide call pageSwapCallback upon next page swap */
-    protected void registerPageSwapCallback() {
-        nativeRegisterPageSwapCallback(mNativeClass);
-    }
-
     /** @hide discard all textures from tiles */
     protected void discardAllTextures() {
         nativeDiscardAllTextures();
@@ -9790,7 +9885,7 @@
     private native int      nativeGetDrawGLFunction(int nativeInstance, Rect rect,
             Rect viewRect, RectF visibleRect, float scale, int extras);
     private native void     nativeUpdateDrawGLFunction(Rect rect, Rect viewRect,
-            RectF visibleRect);
+            RectF visibleRect, float scale);
     private native void     nativeExtendSelection(int x, int y);
     private native int      nativeFindAll(String findLower, String findUpper,
             boolean sameAsLastSearch);
@@ -9841,7 +9936,6 @@
     private native boolean  nativeMoveCursor(int keyCode, int count,
             boolean noScroll);
     private native int      nativeMoveGeneration();
-    private native void     nativeMoveSelection(int x, int y);
     /**
      * @return true if the page should get the shift and arrow keys, rather
      * than select text/navigation.
@@ -9851,24 +9945,16 @@
      */
     private native boolean  nativePageShouldHandleShiftAndArrows();
     private native boolean  nativePointInNavCache(int x, int y, int slop);
-    // Like many other of our native methods, you must make sure that
-    // mNativeClass is not null before calling this method.
-    private native void     nativeResetSelection();
-    private native Point    nativeSelectableText();
-    private native void     nativeSelectAll();
     private native void     nativeSelectBestAt(Rect rect);
     private native void     nativeSelectAt(int x, int y);
-    private native int      nativeSelectionX();
-    private native int      nativeSelectionY();
     private native int      nativeFindIndex();
     private native void     nativeSetExtendSelection();
     private native void     nativeSetFindIsEmpty();
     private native void     nativeSetFindIsUp(boolean isUp);
     private native void     nativeSetHeightCanMeasure(boolean measure);
-    private native void     nativeSetBaseLayer(int nativeInstance,
+    private native boolean  nativeSetBaseLayer(int nativeInstance,
             int layer, Region invalRegion,
-            boolean showVisualIndicator, boolean isPictureAfterFirstLayout,
-            boolean registerPageSwapCallback);
+            boolean showVisualIndicator, boolean isPictureAfterFirstLayout);
     private native int      nativeGetBaseLayer();
     private native void     nativeShowCursorTimed();
     private native void     nativeReplaceBaseContent(int content);
@@ -9880,7 +9966,6 @@
     private native void     nativeStopGL();
     private native Rect     nativeSubtractLayers(Rect content);
     private native int      nativeTextGeneration();
-    private native void     nativeRegisterPageSwapCallback(int nativeInstance);
     private native void     nativeDiscardAllTextures();
     private native void     nativeTileProfilingStart();
     private native float    nativeTileProfilingStop();
@@ -9915,12 +10000,14 @@
     private native int      nativeGetBackgroundColor();
     native boolean  nativeSetProperty(String key, String value);
     native String   nativeGetProperty(String key);
-    private native void     nativeGetTextSelectionRegion(int instance, Region region);
-    private native void     nativeGetSelectionHandles(int instance, int[] handles);
     /**
      * See {@link ComponentCallbacks2} for the trim levels and descriptions
      */
     private static native void     nativeOnTrimMemory(int level);
     private static native void nativeSetPauseDrawing(int instance, boolean pause);
     private static native boolean nativeDisableNavcache();
+    private static native void nativeSetTextSelection(int instance, int selection);
+    private static native int nativeGetHandleLayerId(int instance, int handle,
+            Rect cursorLocation);
+    private static native boolean nativeIsBaseFirst(int instance);
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index fe5c04c..8a9c12d 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -647,18 +647,6 @@
             int end, int textGeneration);
 
     /**
-     * Delete text near the cursor.
-     * @param nativeClass The pointer to the native class (mNativeClass)
-     * @param leftLength The number of characters to the left of the cursor to
-     * delete
-     * @param rightLength The number of characters to the right of the cursor
-     * to delete.
-     */
-    private native void nativeDeleteSurroundingText(int nativeClass,
-            int leftLength,
-            int rightLength);
-
-    /**
      *  Set the selection to (start, end) in the focused textfield. If start and
      *  end are out of order, swap them.
      * @param  nativeClass Pointer to the C++ WebViewCore object mNativeClass
@@ -847,12 +835,14 @@
     }
 
     static class TextSelectionData {
-        public TextSelectionData(int start, int end) {
+        public TextSelectionData(int start, int end, int selectTextPtr) {
             mStart = start;
             mEnd = end;
+            mSelectTextPtr = selectTextPtr;
         }
         int mStart;
         int mEnd;
+        int mSelectTextPtr;
     }
 
     static class TouchUpData {
@@ -882,6 +872,7 @@
         Rect[] mTouchRects;
         boolean mEditable;
         int mTapHighlightColor = WebView.HIGHLIGHT_COLOR;
+        Rect[] mEnclosingParentRects;
 
         // These are the input values that produced this hit test
         int mHitTestX;
@@ -1130,6 +1121,9 @@
         static final int COPY_TEXT = 210;
         static final int DELETE_TEXT = 211;
         static final int INSERT_TEXT = 212;
+        static final int SELECT_TEXT = 213;
+        static final int SELECT_WORD_AT = 214;
+        static final int SELECT_ALL = 215;
 
         // Private handler for WebCore messages.
         private Handler mHandler;
@@ -1206,7 +1200,6 @@
                                 mSettings.onDestroyed();
                                 mNativeClass = 0;
                                 mWebView = null;
-                                WebCoreThreadWatchdog.quit();
                             }
                             break;
 
@@ -1576,11 +1569,6 @@
                                     deleteSelectionData.mStart, deleteSelectionData.mEnd, msg.arg1);
                             break;
 
-                        case DELETE_SURROUNDING_TEXT:
-                            nativeDeleteSurroundingText(mNativeClass,
-                                    msg.arg1, msg.arg2);
-                            break;
-
                         case SET_SELECTION:
                             nativeSetSelection(mNativeClass, msg.arg1, msg.arg2);
                             break;
@@ -1764,6 +1752,25 @@
                         case INSERT_TEXT:
                             nativeInsertText(mNativeClass, (String) msg.obj);
                             break;
+                        case SELECT_TEXT: {
+                            int[] args = (int[]) msg.obj;
+                            if (args == null) {
+                                nativeClearTextSelection(mNativeClass);
+                            } else {
+                                nativeSelectText(mNativeClass, args[0],
+                                        args[1], args[2], args[3]);
+                            }
+                            break;
+                        }
+                        case SELECT_WORD_AT: {
+                            int x = msg.arg1;
+                            int y = msg.arg2;
+                            nativeSelectWordAt(mNativeClass, x, y);
+                            break;
+                        }
+                        case SELECT_ALL:
+                            nativeSelectAll(mNativeClass);
+                            break;
                     }
                 }
             };
@@ -2163,7 +2170,36 @@
                 .obtainMessage(WebView.INVAL_RECT_MSG_ID));
     }
 
+    private Boolean m_skipDrawFlag = false;
+    private boolean m_drawWasSkipped = false;
+
+    void pauseWebKitDraw() {
+        synchronized (m_skipDrawFlag) {
+            if (!m_skipDrawFlag) {
+                m_skipDrawFlag = true;
+            }
+        }
+    }
+
+    void resumeWebKitDraw() {
+        synchronized (m_skipDrawFlag) {
+            if (m_skipDrawFlag && m_drawWasSkipped) {
+                // a draw was dropped, send a retry
+                m_drawWasSkipped = false;
+                mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
+            }
+            m_skipDrawFlag = false;
+        }
+    }
+
     private void webkitDraw() {
+        synchronized (m_skipDrawFlag) {
+            if (m_skipDrawFlag) {
+                m_drawWasSkipped = true;
+                return;
+            }
+        }
+
         mDrawIsScheduled = false;
         DrawData draw = new DrawData();
         if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw start");
@@ -2172,7 +2208,7 @@
         if (draw.mBaseLayer == 0) {
             if (mWebView != null && !mWebView.isPaused()) {
                 if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw abort, resending draw message");
-                mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW));
+                mEventHub.sendMessageDelayed(Message.obtain(null, EventHub.WEBKIT_DRAW), 10);
             } else {
                 if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw abort, webview paused");
             }
@@ -2717,11 +2753,11 @@
 
     // called by JNI
     private void updateTextSelection(int pointer, int start, int end,
-            int textGeneration) {
+            int textGeneration, int selectionPtr) {
         if (mWebView != null) {
             Message.obtain(mWebView.mPrivateHandler,
                 WebView.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration,
-                new TextSelectionData(start, end)).sendToTarget();
+                new TextSelectionData(start, end, selectionPtr)).sendToTarget();
         }
     }
 
@@ -2739,6 +2775,19 @@
                 WebView.FIND_AGAIN).sendToTarget();
     }
 
+    // called by JNI
+    private void initEditField(int pointer, String text, int start, int end) {
+        if (mWebView == null) {
+            return;
+        }
+        Message.obtain(mWebView.mPrivateHandler,
+                WebView.INIT_EDIT_FIELD, pointer, 0, text).sendToTarget();
+        Message.obtain(mWebView.mPrivateHandler,
+                WebView.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer,
+                0, new TextSelectionData(start, end, 0))
+                .sendToTarget();
+    }
+
     private native void nativeUpdateFrameCacheIfLoading(int nativeClass);
     private native void nativeRevealSelection(int nativeClass);
     private native String nativeRequestLabel(int nativeClass, int framePtr,
@@ -2774,17 +2823,6 @@
     }
 
     // called by JNI
-    private void requestKeyboardWithSelection(int pointer, int selStart,
-            int selEnd, int textGeneration) {
-        if (mWebView != null) {
-            Message.obtain(mWebView.mPrivateHandler,
-                    WebView.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer,
-                    textGeneration, new TextSelectionData(selStart, selEnd))
-                    .sendToTarget();
-        }
-    }
-
-    // called by JNI
     private void requestKeyboard(boolean showKeyboard) {
         if (mWebView != null) {
             Message.obtain(mWebView.mPrivateHandler,
@@ -3034,4 +3072,9 @@
      */
     private native String nativeGetText(int nativeClass,
             int startX, int startY, int endX, int endY);
+    private native void nativeSelectText(int nativeClass,
+            int startX, int startY, int endX, int endY);
+    private native void nativeClearTextSelection(int nativeClass);
+    private native void nativeSelectWordAt(int nativeClass, int x, int y);
+    private native void nativeSelectAll(int nativeClass);
 }
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 8ffba64..369e883 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -258,6 +258,7 @@
             // Remember the current zoom density before it gets changed.
             final float originalDefault = mDefaultScale;
             // set the new default density
+            mDisplayDensity = density;
             setDefaultZoomScale(density);
             float scaleChange = (originalDefault > 0.0) ? density / originalDefault: 1.0f;
             // adjust the scale if it falls outside the new zoom bounds
@@ -717,7 +718,7 @@
     private void zoomToReadingLevel() {
         final float readingScale = getReadingLevelScale();
 
-        int left = mWebView.nativeGetBlockLeftEdge(mAnchorX, mAnchorY, mActualScale);
+        int left = mWebView.getBlockLeftEdge(mAnchorX, mAnchorY, readingScale);
         if (left != WebView.NO_LEFTEDGE) {
             // add a 5pt padding to the left edge.
             int viewLeft = mWebView.contentToViewX(left < 5 ? 0 : (left - 5))
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 60b24bc..be6b4e2 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -33,8 +33,6 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
 import android.widget.ActivityChooserModel.ActivityChooserModelClient;
 
 /**
@@ -366,7 +364,7 @@
             getListPopupWindow().dismiss();
             ViewTreeObserver viewTreeObserver = getViewTreeObserver();
             if (viewTreeObserver.isAlive()) {
-                viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
+                viewTreeObserver.removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
             }
         }
         return true;
@@ -400,7 +398,7 @@
         }
         ViewTreeObserver viewTreeObserver = getViewTreeObserver();
         if (viewTreeObserver.isAlive()) {
-            viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
+            viewTreeObserver.removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
         }
         mIsAttachedToWindow = false;
     }
@@ -547,6 +545,7 @@
                         position = mAdapter.getShowDefaultActivity() ? position : position + 1;
                         Intent launchIntent = mAdapter.getDataModel().chooseActivity(position);
                         if (launchIntent != null) {
+                            launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                             mContext.startActivity(launchIntent);
                         }
                     }
@@ -564,6 +563,7 @@
                 final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity);
                 Intent launchIntent = mAdapter.getDataModel().chooseActivity(index);
                 if (launchIntent != null) {
+                    launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                     mContext.startActivity(launchIntent);
                 }
             } else if (view == mExpandActivityOverflowButton) {
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index e226d37..bb00049 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -558,7 +558,9 @@
             mCurrentWindowEnd = newWindowEnd;
             mCurrentWindowStartUnbounded = newWindowStartUnbounded;
             if (mRemoteViewsAdapter != null) {
-                mRemoteViewsAdapter.setVisibleRangeHint(mCurrentWindowStart, mCurrentWindowEnd);
+                int adapterStart = modulo(mCurrentWindowStart, adapterCount);
+                int adapterEnd = modulo(mCurrentWindowEnd, adapterCount);
+                mRemoteViewsAdapter.setVisibleRangeHint(adapterStart, adapterEnd);
             }
         }
         requestLayout();
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 7d58011..ea40dc2 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -212,6 +212,7 @@
     static final int PRF = 1;
     static final int MAX_SIZE = 100000;
     static final int DEFAULT_CONTAINER_MARGIN = 0;
+    static final int UNINITIALIZED_HASH = 0;
 
     // Defaults
 
@@ -240,6 +241,7 @@
     boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
     int alignmentMode = DEFAULT_ALIGNMENT_MODE;
     int defaultGap;
+    int lastLayoutParamsHashCode = UNINITIALIZED_HASH;
 
     // Constructors
 
@@ -566,6 +568,10 @@
                 return FILL;
             case AXIS_SPECIFIED:
                 return CENTER;
+            case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | RELATIVE_LAYOUT_DIRECTION):
+                return START;
+            case (AXIS_SPECIFIED | AXIS_PULL_AFTER | RELATIVE_LAYOUT_DIRECTION):
+                return END;
             default:
                 return UNDEFINED_ALIGNMENT;
         }
@@ -590,7 +596,8 @@
         Spec spec = horizontal ? p.columnSpec : p.rowSpec;
         Axis axis = horizontal ? horizontalAxis : verticalAxis;
         Interval span = spec.span;
-        boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
+        boolean leading1 = (horizontal && isLayoutRtl()) ? !leading : leading;
+        boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount());
 
         return getDefaultMargin(c, isAtEdge, horizontal, leading);
     }
@@ -663,7 +670,7 @@
         int[] maxSizes = new int[count];
 
         for (int i = 0, N = getChildCount(); i < N; i++) {
-            LayoutParams lp = getLayoutParams1(getChildAt(i));
+            LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
 
             final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec;
             final Interval majorRange = majorSpec.span;
@@ -708,6 +715,7 @@
 
             minor = minor + minorSpan;
         }
+        lastLayoutParamsHashCode = computeLayoutParamsHashCode();
         invalidateStructure();
     }
 
@@ -728,8 +736,11 @@
         }
     }
 
-    private LayoutParams getLayoutParams1(View c) {
-        return (LayoutParams) c.getLayoutParams();
+    /** @hide */
+    @Override
+    protected void onSetLayoutParams(View child, ViewGroup.LayoutParams layoutParams) {
+        super.onSetLayoutParams(child, layoutParams);
+        invalidateStructure();
     }
 
     final LayoutParams getLayoutParams(View c) {
@@ -737,7 +748,7 @@
             validateLayoutParams();
             layoutParamsValid = true;
         }
-        return getLayoutParams1(c);
+        return (LayoutParams) c.getLayoutParams();
     }
 
     @Override
@@ -760,10 +771,15 @@
     private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
         int dx = getPaddingLeft();
         int dy = getPaddingTop();
-        graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
+        if (isLayoutRtl()) {
+            int width = getWidth();
+            graphics.drawLine(width - dx - x1, dy + y1, width - dx - x2, dy + y2, paint);
+        } else {
+            graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
+        }
     }
 
-    private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) {
+    private void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) {
         canvas.drawRect(x1, y1, x2 - 1, y2 - 1, paint);
     }
 
@@ -842,17 +858,36 @@
      * @hide
      */
     @Override
-    protected void onChildVisibilityChanged(View child, int visibility) {
-        super.onChildVisibilityChanged(child, visibility);
-        invalidateStructure();
+    protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
+        super.onChildVisibilityChanged(child, oldVisibility, newVisibility);
+        if (oldVisibility == GONE || newVisibility == GONE) {
+            invalidateStructure();
+        }
+    }
+
+    private int computeLayoutParamsHashCode() {
+        int result = 1;
+        for (int i = 0, N = getChildCount(); i < N; i++) {
+            View c = getChildAt(i);
+            if (c.getVisibility() == View.GONE) continue;
+            LayoutParams lp = (LayoutParams) c.getLayoutParams();
+            result = 31 * result + lp.hashCode();
+        }
+        return result;
+    }
+
+    private void checkForLayoutParamsModification() {
+        int layoutParamsHashCode = computeLayoutParamsHashCode();
+        if (lastLayoutParamsHashCode != UNINITIALIZED_HASH &&
+                lastLayoutParamsHashCode != layoutParamsHashCode) {
+            invalidateStructure();
+            Log.w(TAG, "The fields of some layout parameters were modified in between layout " +
+                    "operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
+        }
     }
 
     // Measurement
 
-    final boolean isGone(View c) {
-        return c.getVisibility() == View.GONE;
-    }
-
     private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
                                           int childWidth, int childHeight) {
         int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
@@ -865,7 +900,7 @@
     private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) {
         for (int i = 0, N = getChildCount(); i < N; i++) {
             View c = getChildAt(i);
-            if (isGone(c)) continue;
+            if (c.getVisibility() == View.GONE) continue;
             LayoutParams lp = getLayoutParams(c);
             if (firstPass) {
                 measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
@@ -890,6 +925,8 @@
 
     @Override
     protected void onMeasure(int widthSpec, int heightSpec) {
+        checkForLayoutParamsModification();
+
         /** If we have been called by {@link View#measure(int, int)}, one of width or height
          *  is  likely to have changed. We must invalidate if so. */
         invalidateValues();
@@ -929,7 +966,7 @@
     }
 
     final int getMeasurementIncludingMargin(View c, boolean horizontal) {
-        if (isGone(c)) {
+        if (c.getVisibility() == View.GONE) {
             return 0;
         }
         return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal);
@@ -943,7 +980,7 @@
 
     final Alignment getAlignment(Alignment alignment, boolean horizontal) {
         return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
-                (horizontal ? LEFT : BASELINE);
+                (horizontal ? START : BASELINE);
     }
 
     // Layout container
@@ -962,6 +999,8 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        checkForLayoutParamsModification();
+
         int targetWidth = right - left;
         int targetHeight = bottom - top;
 
@@ -978,7 +1017,7 @@
 
         for (int i = 0, N = getChildCount(); i < N; i++) {
             View c = getChildAt(i);
-            if (isGone(c)) continue;
+            if (c.getVisibility() == View.GONE) continue;
             LayoutParams lp = getLayoutParams(c);
             Spec columnSpec = lp.columnSpec;
             Spec rowSpec = lp.rowSpec;
@@ -1001,41 +1040,41 @@
             Alignment hAlign = getAlignment(columnSpec.alignment, true);
             Alignment vAlign = getAlignment(rowSpec.alignment, false);
 
-            int dx, dy;
-
             Bounds colBounds = horizontalAxis.getGroupBounds().getValue(i);
             Bounds rowBounds = verticalAxis.getGroupBounds().getValue(i);
 
             // Gravity offsets: the location of the alignment group relative to its cell group.
             //noinspection NullableProblems
-            int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(true)));
+            int gravityOffsetX = protect(hAlign.getAlignmentValue(null,
+                    cellWidth - colBounds.size(true)));
             //noinspection NullableProblems
-            int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(true)));
+            int gravityOffsetY = protect(vAlign.getAlignmentValue(null,
+                    cellHeight - rowBounds.size(true)));
 
-            int leftMargin = getMargin(c, true, true);
+            boolean rtl = isLayoutRtl();
+            int startMargin = getMargin(c, true, !rtl);
             int topMargin = getMargin(c, false, true);
-            int rightMargin = getMargin(c, true, false);
+            int endMargin = getMargin(c, true, rtl);
             int bottomMargin = getMargin(c, false, false);
 
             // Same calculation as getMeasurementIncludingMargin()
-            int mWidth = leftMargin + pWidth + rightMargin;
+            int mWidth = startMargin + pWidth + endMargin;
             int mHeight = topMargin + pHeight + bottomMargin;
 
             // Alignment offsets: the location of the view relative to its alignment group.
-            int a2vx = colBounds.getOffset(c, hAlign, mWidth);
-            int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
+            int alignmentOffsetX = colBounds.getOffset(c, hAlign, mWidth);
+            int alignmentOffsetY = rowBounds.getOffset(c, vAlign, mHeight);
 
-            dx = c2ax + a2vx + leftMargin;
-            dy = c2ay + a2vy + topMargin;
+            int dx = gravityOffsetX + alignmentOffsetX + startMargin;
+            int dy = gravityOffsetY + alignmentOffsetY + topMargin;
 
-            cellWidth -= leftMargin + rightMargin;
+            cellWidth -= startMargin + endMargin;
             cellHeight -= topMargin + bottomMargin;
 
-            int type = PRF;
-            int width = hAlign.getSizeInCell(c, pWidth, cellWidth, type);
-            int height = vAlign.getSizeInCell(c, pHeight, cellHeight, type);
+            int width = hAlign.getSizeInCell(c, pWidth, cellWidth, PRF);
+            int height = vAlign.getSizeInCell(c, pHeight, cellHeight, PRF);
 
-            int cx = paddingLeft + x1 + dx;
+            int cx = rtl ? targetWidth - paddingRight - x1 - dx - width : paddingLeft + x1 + dx;
             int cy = paddingTop + y1 + dy;
             if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) {
                 c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
@@ -1515,7 +1554,7 @@
             int[] margins = leading ? leadingMargins : trailingMargins;
             for (int i = 0, N = getChildCount(); i < N; i++) {
                 View c = getChildAt(i);
-                if (isGone(c)) continue;
+                if (c.getVisibility() == View.GONE) continue;
                 LayoutParams lp = getLayoutParams(c);
                 Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
                 Interval span = spec.span;
@@ -1755,12 +1794,28 @@
         /**
          * The spec that defines the vertical characteristics of the cell group
          * described by these layout parameters.
+         * If an assignment is made to this field after a measurement or layout operation
+         * has already taken place, a call to
+         * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
+         * must be made to notify GridLayout of the change. GridLayout is normally able
+         * to detect when code fails to observe this rule, issue a warning and take steps to
+         * compensate for the omission. This facility is implemented on a best effort basis
+         * and should not be relied upon in production code - so it is best to include the above
+         * calls to remove the warnings as soon as it is practical.
          */
         public Spec rowSpec = Spec.UNDEFINED;
 
         /**
          * The spec that defines the horizontal characteristics of the cell group
          * described by these layout parameters.
+         * If an assignment is made to this field after a measurement or layout operation
+         * has already taken place, a call to
+         * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
+         * must be made to notify GridLayout of the change. GridLayout is normally able
+         * to detect when code fails to observe this rule, issue a warning and take steps to
+         * compensate for the omission. This facility is implemented on a best effort basis
+         * and should not be relied upon in production code - so it is best to include the above
+         * calls to remove the warnings as soon as it is practical.
          */
         public Spec columnSpec = Spec.UNDEFINED;
 
@@ -1905,6 +1960,26 @@
         final void setColumnSpecSpan(Interval span) {
             columnSpec = columnSpec.copyWriteSpan(span);
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            LayoutParams that = (LayoutParams) o;
+
+            if (!columnSpec.equals(that.columnSpec)) return false;
+            if (!rowSpec.equals(that.rowSpec)) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = rowSpec.hashCode();
+            result = 31 * result + columnSpec.hashCode();
+            return result;
+        }
     }
 
     /*
@@ -2047,7 +2122,7 @@
     /*
     For each group (with a given alignment) we need to store the amount of space required
     before the alignment point and the amount of space required after it. One side of this
-    calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this.
+    calculation is always 0 for START and END alignments but we don't make use of this.
     For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
     simple optimisations are possible.
 
@@ -2403,18 +2478,29 @@
     }
 
     static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return UNDEFINED;
         }
     };
 
+    /**
+     * Indicates that a view should be aligned with the <em>start</em>
+     * edges of the other views in its cell group.
+     */
     private static final Alignment LEADING = new Alignment() {
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return 0;
         }
     };
 
+    /**
+     * Indicates that a view should be aligned with the <em>end</em>
+     * edges of the other views in its cell group.
+     */
     private static final Alignment TRAILING = new Alignment() {
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return viewSize;
         }
@@ -2433,16 +2519,41 @@
     public static final Alignment BOTTOM = TRAILING;
 
     /**
-     * Indicates that a view should be aligned with the <em>right</em>
+     * Indicates that a view should be aligned with the <em>start</em>
      * edges of the other views in its cell group.
      */
-    public static final Alignment RIGHT = TRAILING;
+    public static final Alignment START = LEADING;
+
+    /**
+     * Indicates that a view should be aligned with the <em>end</em>
+     * edges of the other views in its cell group.
+     */
+    public static final Alignment END = TRAILING;
+
+    private static Alignment getAbsoluteAlignment(final Alignment a1, final Alignment a2) {
+        return new Alignment() {
+            @Override
+            public int getAlignmentValue(View view, int viewSize) {
+                if (view == null) {
+                    return UNDEFINED;
+                }
+                Alignment alignment = view.isLayoutRtl() ? a2 : a1;
+                return alignment.getAlignmentValue(view, viewSize);
+            }
+        };
+    }
 
     /**
      * Indicates that a view should be aligned with the <em>left</em>
      * edges of the other views in its cell group.
      */
-    public static final Alignment LEFT = LEADING;
+    public static final Alignment LEFT = getAbsoluteAlignment(START, END);
+
+    /**
+     * Indicates that a view should be aligned with the <em>right</em>
+     * edges of the other views in its cell group.
+     */
+    public static final Alignment RIGHT = getAbsoluteAlignment(END, START);
 
     /**
      * Indicates that a view should be <em>centered</em> with the other views in its cell group.
@@ -2450,6 +2561,7 @@
      * LayoutParams#columnSpec columnSpecs}.
      */
     public static final Alignment CENTER = new Alignment() {
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return viewSize >> 1;
         }
@@ -2463,6 +2575,7 @@
      * @see View#getBaseline()
      */
     public static final Alignment BASELINE = new Alignment() {
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             if (view == null) {
                 return UNDEFINED;
@@ -2513,6 +2626,7 @@
      * {@link LayoutParams#columnSpec columnSpecs}.
      */
     public static final Alignment FILL = new Alignment() {
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return UNDEFINED;
         }
@@ -2528,6 +2642,5 @@
     }
 
     private static final int INFLEXIBLE = 0;
-
     private static final int CAN_STRETCH = 2;
 }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e20d12a..67fd059 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1651,6 +1651,7 @@
                 // are focusable
                 if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
                     final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
+                            focusLayoutRestoreView != null &&
                             focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
                     if (!focusWasTaken) {
                         // selected item didn't take focus, fine, but still want
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 8628ab11..84e86af 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -56,13 +56,13 @@
 /**
  * A widget that enables the user to select a number form a predefined range.
  * The widget presents an input field and up and down buttons for selecting the
- * current value. Pressing/long pressing the up and down buttons increments and
+ * current value. Pressing/long-pressing the up and down buttons increments and
  * decrements the current value respectively. Touching the input field shows a
- * scroll wheel, tapping on which while shown and not moving allows direct edit
- * of the current value. Sliding motions up or down hide the buttons and the
- * input field, show the scroll wheel, and rotate the latter. Flinging is
+ * scroll wheel, which when touched allows direct edit
+ * of the current value. Sliding gestures up or down hide the buttons and the
+ * input filed, show and rotate the scroll wheel. Flinging is
  * also supported. The widget enables mapping from positions to strings such
- * that instead the position index the corresponding string is displayed.
+ * that, instead of the position index, the corresponding string is displayed.
  * <p>
  * For an example of using this widget, see {@link android.widget.TimePicker}.
  * </p>
@@ -71,6 +71,11 @@
 public class NumberPicker extends LinearLayout {
 
     /**
+     * The number of items show in the selector wheel.
+     */
+    public static final int SELECTOR_WHEEL_ITEM_COUNT = 5;
+
+    /**
      * The default update interval during long press.
      */
     private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300;
@@ -1137,14 +1142,17 @@
      * items shown on the selector wheel) the selector wheel wrapping is
      * enabled.
      * </p>
-     *
+     * <p>
+     * <strong>Note:</strong> If the number of items, i.e. the range
+     * ({@link #getMaxValue()} - {@link #getMinValue()}) is less than
+     * {@link #SELECTOR_WHEEL_ITEM_COUNT}, the selector wheel will not
+     * wrap. Hence, in such a case calling this method is a NOP.
+     * </p>
      * @param wrapSelectorWheel Whether to wrap.
      */
     public void setWrapSelectorWheel(boolean wrapSelectorWheel) {
-        if (wrapSelectorWheel && (mMaxValue - mMinValue) < mSelectorIndices.length) {
-            throw new IllegalStateException("Range less than selector items count.");
-        }
-        if (wrapSelectorWheel != mWrapSelectorWheel) {
+        final boolean wrappingAllowed = (mMaxValue - mMinValue) >= mSelectorIndices.length;
+        if ((!wrapSelectorWheel || wrappingAllowed) && wrapSelectorWheel != mWrapSelectorWheel) {
             mWrapSelectorWheel = wrapSelectorWheel;
             updateIncrementAndDecrementButtonsVisibilityState();
         }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 1592061..62afd61 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -427,13 +427,22 @@
 
         public SetOnClickPendingIntent(Parcel parcel) {
             viewId = parcel.readInt();
-            pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
+
+            // We check a flag to determine if the parcel contains a PendingIntent.
+            if (parcel.readInt() != 0) {
+                pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(parcel);
+            }
         }
 
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(TAG);
             dest.writeInt(viewId);
-            pendingIntent.writeToParcel(dest, 0 /* no flags */);
+
+            // We use a flag to indicate whether the parcel contains a valid object.
+            dest.writeInt(pendingIntent != null ? 1 : 0);
+            if (pendingIntent != null) {
+                pendingIntent.writeToParcel(dest, 0 /* no flags */);
+            }
         }
 
         @Override
@@ -445,35 +454,39 @@
             // sense, do they mean to set a PendingIntent template for the AdapterView's children?
             if (mIsWidgetCollectionChild) {
                 Log.e("RemoteViews", "Cannot setOnClickPendingIntent for collection item " +
-				"(id: " + viewId + ")");
+                        "(id: " + viewId + ")");
                 // TODO: return; We'll let this slide until apps are up to date.
             }
 
-            if (target != null && pendingIntent != null) {
-                OnClickListener listener = new OnClickListener() {
-                    public void onClick(View v) {
-                        // Find target view location in screen coordinates and
-                        // fill into PendingIntent before sending.
-                        final float appScale = v.getContext().getResources()
-                                .getCompatibilityInfo().applicationScale;
-                        final int[] pos = new int[2];
-                        v.getLocationOnScreen(pos);
-
-                        final Rect rect = new Rect();
-                        rect.left = (int) (pos[0] * appScale + 0.5f);
-                        rect.top = (int) (pos[1] * appScale + 0.5f);
-                        rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
-                        rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
-
-                        final Intent intent = new Intent();
-                        intent.setSourceBounds(rect);
-                        startIntentSafely(v.getContext(), pendingIntent, intent);
-                    }
-                };
+            if (target != null) {
+                // If the pendingIntent is null, we clear the onClickListener
+                OnClickListener listener = null;
+                if (pendingIntent != null) {
+                    listener = new OnClickListener() {
+                        public void onClick(View v) {
+                            // Find target view location in screen coordinates and
+                            // fill into PendingIntent before sending.
+                            final float appScale = v.getContext().getResources()
+                                    .getCompatibilityInfo().applicationScale;
+                            final int[] pos = new int[2];
+                            v.getLocationOnScreen(pos);
+    
+                            final Rect rect = new Rect();
+                            rect.left = (int) (pos[0] * appScale + 0.5f);
+                            rect.top = (int) (pos[1] * appScale + 0.5f);
+                            rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
+                            rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
+    
+                            final Intent intent = new Intent();
+                            intent.setSourceBounds(rect);
+                            startIntentSafely(v.getContext(), pendingIntent, intent);
+                        }
+                    };
+                }
                 target.setOnClickListener(listener);
             }
         }
-        
+
         int viewId;
         PendingIntent pendingIntent;
 
@@ -667,6 +680,9 @@
                 Log.d("RemoteViews", "read viewId=0x" + Integer.toHexString(this.viewId)
                         + " methodName=" + this.methodName + " type=" + this.type);
             }
+
+            // For some values that may have been null, we first check a flag to see if they were
+            // written to the parcel.
             switch (this.type) {
                 case BOOLEAN:
                     this.value = in.readInt() != 0;
@@ -699,16 +715,22 @@
                     this.value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
                     break;
                 case URI:
-                    this.value = Uri.CREATOR.createFromParcel(in);
+                    if (in.readInt() != 0) {
+                        this.value = Uri.CREATOR.createFromParcel(in);
+                    }
                     break;
                 case BITMAP:
-                    this.value = Bitmap.CREATOR.createFromParcel(in);
+                    if (in.readInt() != 0) {
+                        this.value = Bitmap.CREATOR.createFromParcel(in);
+                    }
                     break;
                 case BUNDLE:
                     this.value = in.readBundle();
                     break;
                 case INTENT:
-                    this.value = Intent.CREATOR.createFromParcel(in);
+                    if (in.readInt() != 0) {
+                        this.value = Intent.CREATOR.createFromParcel(in);
+                    }
                     break;
                 default:
                     break;
@@ -725,6 +747,9 @@
                 Log.d("RemoteViews", "write viewId=0x" + Integer.toHexString(this.viewId)
                         + " methodName=" + this.methodName + " type=" + this.type);
             }
+
+            // For some values which are null, we record an integer flag to indicate whether
+            // we have written a valid value to the parcel.
             switch (this.type) {
                 case BOOLEAN:
                     out.writeInt((Boolean) this.value ? 1 : 0);
@@ -757,16 +782,25 @@
                     TextUtils.writeToParcel((CharSequence)this.value, out, flags);   
                     break;
                 case URI:
-                    ((Uri)this.value).writeToParcel(out, flags);
+                    out.writeInt(this.value != null ? 1 : 0);
+                    if (this.value != null) {
+                        ((Uri)this.value).writeToParcel(out, flags);
+                    }
                     break;
                 case BITMAP:
-                    ((Bitmap)this.value).writeToParcel(out, flags);
+                    out.writeInt(this.value != null ? 1 : 0);
+                    if (this.value != null) {
+                        ((Bitmap)this.value).writeToParcel(out, flags);
+                    }
                     break;
                 case BUNDLE:
                     out.writeBundle((Bundle) this.value);
                     break;
                 case INTENT:
-                    ((Intent)this.value).writeToParcel(out, flags);
+                    out.writeInt(this.value != null ? 1 : 0);
+                    if (this.value != null) {
+                        ((Intent)this.value).writeToParcel(out, flags);
+                    }
                     break;
                 default:
                     break;
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index bb27b73..22e9ef1 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -279,6 +279,7 @@
             final int itemId = item.getItemId();
             Intent launchIntent = dataModel.chooseActivity(itemId);
             if (launchIntent != null) {
+                launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                 mContext.startActivity(launchIntent);
             }
             return true;
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index a106159..909f383 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -102,7 +102,8 @@
 
         mTextServicesManager = (TextServicesManager) mTextView.getContext().
                 getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
-        if (!mTextServicesManager.isSpellCheckerEnabled()) {
+        if (!mTextServicesManager.isSpellCheckerEnabled()
+                ||  mTextServicesManager.getCurrentSpellCheckerSubtype(true) == null) {
             mSpellCheckerSession = null;
         } else {
             mSpellCheckerSession = mTextServicesManager.newSpellCheckerSession(
@@ -341,56 +342,15 @@
         final int end = editable.getSpanEnd(spellCheckSpan);
         if (start < 0 || end <= start) return; // span was removed in the meantime
 
-        // Other suggestion spans may exist on that region, with identical suggestions, filter
-        // them out to avoid duplicates.
-        SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class);
-        final int length = suggestionSpans.length;
-        for (int i = 0; i < length; i++) {
-            final int spanStart = editable.getSpanStart(suggestionSpans[i]);
-            final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
-            if (spanStart != start || spanEnd != end) {
-                // Nulled (to avoid new array allocation) if not on that exact same region
-                suggestionSpans[i] = null;
-            }
-        }
-
         final int suggestionsCount = suggestionsInfo.getSuggestionsCount();
-        String[] suggestions;
         if (suggestionsCount <= 0) {
             // A negative suggestion count is possible
-            suggestions = ArrayUtils.emptyArray(String.class);
-        } else {
-            int numberOfSuggestions = 0;
-            suggestions = new String[suggestionsCount];
+            return;
+        }
 
-            for (int i = 0; i < suggestionsCount; i++) {
-                final String spellSuggestion = suggestionsInfo.getSuggestionAt(i);
-                if (spellSuggestion == null) break;
-                boolean suggestionFound = false;
-
-                for (int j = 0; j < length && !suggestionFound; j++) {
-                    if (suggestionSpans[j] == null) break;
-
-                    String[] suggests = suggestionSpans[j].getSuggestions();
-                    for (int k = 0; k < suggests.length; k++) {
-                        if (spellSuggestion.equals(suggests[k])) {
-                            // The suggestion is already provided by an other SuggestionSpan
-                            suggestionFound = true;
-                            break;
-                        }
-                    }
-                }
-
-                if (!suggestionFound) {
-                    suggestions[numberOfSuggestions++] = spellSuggestion;
-                }
-            }
-
-            if (numberOfSuggestions != suggestionsCount) {
-                String[] newSuggestions = new String[numberOfSuggestions];
-                System.arraycopy(suggestions, 0, newSuggestions, 0, numberOfSuggestions);
-                suggestions = newSuggestions;
-            }
+        String[] suggestions = new String[suggestionsCount];
+        for (int i = 0; i < suggestionsCount; i++) {
+            suggestions[i] = suggestionsInfo.getSuggestionAt(i);
         }
 
         SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
@@ -466,7 +426,8 @@
                     }
 
                     // A new word has been created across the interval boundaries with this edit.
-                    // Previous spans (ended on start / started on end) removed, not valid anymore
+                    // The previous spans (that ended on start / started on end) are not valid
+                    // anymore and must be removed.
                     if (wordStart < start && wordEnd > start) {
                         removeSpansAt(editable, start, spellCheckSpans);
                         removeSpansAt(editable, start, suggestionSpans);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 04f4a83..7db8a1e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -256,10 +256,7 @@
 
     private float mShadowRadius, mShadowDx, mShadowDy;
 
-    private static final int PREDRAW_NOT_REGISTERED = 0;
-    private static final int PREDRAW_PENDING = 1;
-    private static final int PREDRAW_DONE = 2;
-    private int mPreDrawState = PREDRAW_NOT_REGISTERED;
+    private boolean mPreDrawRegistered;
 
     private TextUtils.TruncateAt mEllipsize = null;
 
@@ -365,8 +362,6 @@
 
     private SpellChecker mSpellChecker;
 
-    private boolean mSoftInputShownOnFocus = true;
-
     // The alignment to pass to Layout, or null if not resolved.
     private Layout.Alignment mLayoutAlignment;
 
@@ -1210,6 +1205,7 @@
             if (imm != null) imm.restartInput(this);
         }
 
+        mTextDisplayListIsValid = false;
         prepareCursorControllers();
 
         // start or stop the cursor blinking as appropriate
@@ -2315,6 +2311,7 @@
     public void setHighlightColor(int color) {
         if (mHighlightColor != color) {
             mHighlightColor = color;
+            mTextDisplayListIsValid = false;
             invalidate();
         }
     }
@@ -2335,6 +2332,7 @@
         mShadowDx = dx;
         mShadowDy = dy;
 
+        mTextDisplayListIsValid = false;
         invalidate();
     }
 
@@ -2384,29 +2382,6 @@
     }
 
     /**
-     * Sets whether the soft input method will be made visible when this
-     * TextView gets focused. The default is true.
-     *
-     * @attr ref android.R.styleable#TextView_softInputShownOnFocus
-     * @hide
-     */
-    @android.view.RemotableViewMethod
-    public final void setSoftInputShownOnFocus(boolean show) {
-        mSoftInputShownOnFocus = show;
-    }
-
-    /**
-     * Returns whether the soft input method will be made visible when this
-     * TextView gets focused. The default is true.
-     *
-     * @attr ref android.R.styleable#TextView_softInputShownOnFocus
-     * @hide
-     */
-    public final boolean getSoftInputShownOnFocus() {
-        return mSoftInputShownOnFocus;
-    }
-
-    /**
      * Returns the list of URLSpans attached to the text
      * (by {@link Linkify} or otherwise) if any.  You can call
      * {@link URLSpan#getURL} on them to find where they link to
@@ -2849,6 +2824,7 @@
             }
         }
         if (inval) {
+            mTextDisplayListIsValid = false;
             invalidate();
         }
     }
@@ -3496,6 +3472,9 @@
         if (mText.length() == 0) {
             invalidate();
         }
+
+        // Invalidate display list if hint will be used
+        if (mText.length() == 0 && mHint != null) mTextDisplayListIsValid = false;
     }
 
     /**
@@ -4387,26 +4366,16 @@
     }
 
     private void registerForPreDraw() {
-        final ViewTreeObserver observer = getViewTreeObserver();
-
-        if (mPreDrawState == PREDRAW_NOT_REGISTERED) {
-            observer.addOnPreDrawListener(this);
-            mPreDrawState = PREDRAW_PENDING;
-        } else if (mPreDrawState == PREDRAW_DONE) {
-            mPreDrawState = PREDRAW_PENDING;
+        if (!mPreDrawRegistered) {
+            getViewTreeObserver().addOnPreDrawListener(this);
+            mPreDrawRegistered = true;
         }
-
-        // else state is PREDRAW_PENDING, so keep waiting.
     }
 
     /**
      * {@inheritDoc}
      */
     public boolean onPreDraw() {
-        if (mPreDrawState != PREDRAW_PENDING) {
-            return true;
-        }
-
         if (mLayout == null) {
             assumeLayout();
         }
@@ -4457,7 +4426,9 @@
             startSelectionActionMode();
         }
 
-        mPreDrawState = PREDRAW_DONE;
+        getViewTreeObserver().removeOnPreDrawListener(this);
+        mPreDrawRegistered = false;
+
         return !changed;
     }
 
@@ -4492,10 +4463,9 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
 
-        final ViewTreeObserver observer = getViewTreeObserver();
-        if (mPreDrawState != PREDRAW_NOT_REGISTERED) {
-            observer.removeOnPreDrawListener(this);
-            mPreDrawState = PREDRAW_NOT_REGISTERED;
+        if (mPreDrawRegistered) {
+            getViewTreeObserver().removeOnPreDrawListener(this);
+            mPreDrawRegistered = false;
         }
 
         if (mError != null) {
@@ -4768,12 +4738,6 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        if (mPreDrawState == PREDRAW_DONE) {
-            final ViewTreeObserver observer = getViewTreeObserver();
-            observer.removeOnPreDrawListener(this);
-            mPreDrawState = PREDRAW_NOT_REGISTERED;
-        }
-
         if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return;
 
         restartMarqueeIfNeeded();
@@ -4877,10 +4841,14 @@
         int extendedPaddingTop = getExtendedPaddingTop();
         int extendedPaddingBottom = getExtendedPaddingBottom();
 
+        final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop;
+        final int maxScrollY = mLayout.getHeight() - vspace;
+
         float clipLeft = compoundPaddingLeft + scrollX;
-        float clipTop = extendedPaddingTop + scrollY;
+        float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY;
         float clipRight = right - left - compoundPaddingRight + scrollX;
-        float clipBottom = bottom - top - extendedPaddingBottom + scrollY;
+        float clipBottom = bottom - top + scrollY -
+                ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom);
 
         if (mShadowRadius != 0) {
             clipLeft += Math.min(0, mShadowDx - mShadowRadius);
@@ -5040,7 +5008,7 @@
             if (mTextDisplayList == null || !mTextDisplayList.isValid() ||
                     !mTextDisplayListIsValid) {
                 if (mTextDisplayList == null) {
-                    mTextDisplayList = getHardwareRenderer().createDisplayList();
+                    mTextDisplayList = getHardwareRenderer().createDisplayList("Text");
                 }
 
                 final HardwareCanvas hardwareCanvas = mTextDisplayList.start();
@@ -5539,7 +5507,7 @@
                                 && mLayout != null && onCheckIsTextEditor()) {
                             InputMethodManager imm = InputMethodManager.peekInstance();
                             viewClicked(imm);
-                            if (imm != null && mSoftInputShownOnFocus) {
+                            if (imm != null) {
                                 imm.showSoftInput(this, 0);
                             }
                         }
@@ -6795,6 +6763,12 @@
         }
     }
 
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (changed) mTextDisplayListIsValid = false;
+    }
+
     /**
      * Returns true if anything changed.
      */
@@ -8386,20 +8360,19 @@
             }
 
             if (touchIsFinished && (isTextEditable() || mTextIsSelectable)) {
-                // Move cursor
-                final int offset = getOffsetForPosition(event.getX(), event.getY());
-                Selection.setSelection((Spannable) mText, offset);
-
                 // Show the IME, except when selecting in read-only text.
                 final InputMethodManager imm = InputMethodManager.peekInstance();
                 viewClicked(imm);
-                if (!mTextIsSelectable && mSoftInputShownOnFocus) {
+                if (!mTextIsSelectable) {
                     handled |= imm != null && imm.showSoftInput(this, 0);
                 }
 
                 boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
                 hideControllers();
                 if (!selectAllGotFocus && mText.length() > 0) {
+                    // Move cursor
+                    final int offset = getOffsetForPosition(event.getX(), event.getY());
+                    Selection.setSelection((Spannable) mText, offset);
                     if (mSpellChecker != null) {
                         // When the cursor moves, the word that was typed may need spell check
                         mSpellChecker.onSelectionChanged();
@@ -9749,11 +9722,12 @@
         public void show() {
             if (!(mText instanceof Editable)) return;
 
-            updateSuggestions();
-            mCursorWasVisibleBeforeSuggestions = mCursorVisible;
-            setCursorVisible(false);
-            mIsShowingUp = true;
-            super.show();
+            if (updateSuggestions()) {
+                mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+                setCursorVisible(false);
+                mIsShowingUp = true;
+                super.show();
+            }
         }
 
         @Override
@@ -9809,11 +9783,13 @@
             super.hide();
         }
 
-        private void updateSuggestions() {
+        private boolean updateSuggestions() {
             Spannable spannable = (Spannable) TextView.this.mText;
             SuggestionSpan[] suggestionSpans = getSuggestionSpans();
 
             final int nbSpans = suggestionSpans.length;
+            // Suggestions are shown after a delay: the underlying spans may have been removed
+            if (nbSpans == 0) return false;
 
             mNumberOfSuggestions = 0;
             int spanUnionStart = mText.length();
@@ -9839,17 +9815,34 @@
                 String[] suggestions = suggestionSpan.getSuggestions();
                 int nbSuggestions = suggestions.length;
                 for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
-                    SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
-                    suggestionInfo.suggestionSpan = suggestionSpan;
-                    suggestionInfo.suggestionIndex = suggestionIndex;
-                    suggestionInfo.text.replace(0, suggestionInfo.text.length(),
-                            suggestions[suggestionIndex]);
+                    String suggestion = suggestions[suggestionIndex];
 
-                    mNumberOfSuggestions++;
-                    if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
-                        // Also end outer for loop
-                        spanIndex = nbSpans;
-                        break;
+                    boolean suggestionIsDuplicate = false;
+                    for (int i = 0; i < mNumberOfSuggestions; i++) {
+                        if (mSuggestionInfos[i].text.toString().equals(suggestion)) {
+                            SuggestionSpan otherSuggestionSpan = mSuggestionInfos[i].suggestionSpan;
+                            final int otherSpanStart = spannable.getSpanStart(otherSuggestionSpan);
+                            final int otherSpanEnd = spannable.getSpanEnd(otherSuggestionSpan);
+                            if (spanStart == otherSpanStart && spanEnd == otherSpanEnd) {
+                                suggestionIsDuplicate = true;
+                                break;
+                            }
+                        }
+                    }
+
+                    if (!suggestionIsDuplicate) {
+                        SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
+                        suggestionInfo.suggestionSpan = suggestionSpan;
+                        suggestionInfo.suggestionIndex = suggestionIndex;
+                        suggestionInfo.text.replace(0, suggestionInfo.text.length(), suggestion);
+
+                        mNumberOfSuggestions++;
+
+                        if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
+                            // Also end outer for loop
+                            spanIndex = nbSpans;
+                            break;
+                        }
                     }
                 }
             }
@@ -9858,7 +9851,7 @@
                 highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
             }
 
-            // Add to dictionary item if there is a span with the misspelled flag
+            // Add "Add to dictionary" item if there is a span with the misspelled flag
             if (misspelledSpan != null) {
                 final int misspelledStart = spannable.getSpanStart(misspelledSpan);
                 final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
@@ -9899,6 +9892,7 @@
                     Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
             mSuggestionsAdapter.notifyDataSetChanged();
+            return true;
         }
 
         private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
@@ -9916,8 +9910,9 @@
                     suggestionInfo.text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
             // Add the text before and after the span.
-            suggestionInfo.text.insert(0, mText.toString().substring(unionStart, spanStart));
-            suggestionInfo.text.append(mText.toString().substring(spanEnd, unionEnd));
+            final String textAsString = text.toString();
+            suggestionInfo.text.insert(0, textAsString.substring(unionStart, spanStart));
+            suggestionInfo.text.append(textAsString.substring(spanEnd, unionEnd));
         }
 
         @Override
@@ -10163,7 +10158,7 @@
         }
 
         final boolean selectionStarted = mSelectionActionMode != null || willExtract;
-        if (selectionStarted && !mTextIsSelectable && mSoftInputShownOnFocus) {
+        if (selectionStarted && !mTextIsSelectable) {
             // Show the IME to be able to replace text, except when selecting non editable text.
             final InputMethodManager imm = InputMethodManager.peekInstance();
             if (imm != null) {
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index edeb2a8..d1aa1ce 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -142,6 +142,14 @@
         return false;
     }
 
+    public static long total(long[] array) {
+        long total = 0;
+        for (long value : array) {
+            total += value;
+        }
+        return total;
+    }
+
     /**
      * Appends an element to a copy of the array and returns the copy.
      * @param array The original array, or null to represent an empty array.
diff --git a/core/java/com/android/internal/util/FastMath.java b/core/java/com/android/internal/util/FastMath.java
index efd0871..88a17e6 100644
--- a/core/java/com/android/internal/util/FastMath.java
+++ b/core/java/com/android/internal/util/FastMath.java
@@ -26,8 +26,8 @@
      * thought it may return slightly different results. It does not try to
      * handle (in any meaningful way) NaN or infinities.
      */
-    public static int round(float x) {
-        long lx = (long)(x * (65536 * 256f));
-        return (int)((lx + 0x800000) >> 24);
+    public static int round(float value) {
+        long lx = (long) (value * (65536 * 256f));
+        return (int) ((lx + 0x800000) >> 24);
     }
 }
diff --git a/core/java/com/android/internal/util/FileRotator.java b/core/java/com/android/internal/util/FileRotator.java
index 3ce95e7..8a8f315 100644
--- a/core/java/com/android/internal/util/FileRotator.java
+++ b/core/java/com/android/internal/util/FileRotator.java
@@ -17,9 +17,9 @@
 package com.android.internal.util;
 
 import android.os.FileUtils;
+import android.util.Slog;
 
-import com.android.internal.util.FileRotator.Reader;
-import com.android.internal.util.FileRotator.Writer;
+import com.android.internal.util.FileRotator.Rewriter;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -41,12 +41,15 @@
  * Instead of manipulating files directly, users implement interfaces that
  * perform operations on {@link InputStream} and {@link OutputStream}. This
  * enables atomic rewriting of file contents in
- * {@link #combineActive(Reader, Writer, long)}.
+ * {@link #rewriteActive(Rewriter, long)}.
  * <p>
  * Users must periodically call {@link #maybeRotate(long)} to perform actual
  * rotation. Not inherently thread safe.
  */
 public class FileRotator {
+    private static final String TAG = "FileRotator";
+    private static final boolean LOGD = true;
+
     private final File mBasePath;
     private final String mPrefix;
     private final long mRotateAgeMillis;
@@ -73,6 +76,15 @@
     }
 
     /**
+     * External class that reads existing data from given {@link InputStream},
+     * then writes any modified data to {@link OutputStream}.
+     */
+    public interface Rewriter extends Reader, Writer {
+        public void reset();
+        public boolean shouldWrite();
+    }
+
+    /**
      * Create a file rotator.
      *
      * @param basePath Directory under which all files will be placed.
@@ -96,6 +108,8 @@
             if (!name.startsWith(mPrefix)) continue;
 
             if (name.endsWith(SUFFIX_BACKUP)) {
+                if (LOGD) Slog.d(TAG, "recovering " + name);
+
                 final File backupFile = new File(mBasePath, name);
                 final File file = new File(
                         mBasePath, name.substring(0, name.length() - SUFFIX_BACKUP.length()));
@@ -104,6 +118,8 @@
                 backupFile.renameTo(file);
 
             } else if (name.endsWith(SUFFIX_NO_BACKUP)) {
+                if (LOGD) Slog.d(TAG, "recovering " + name);
+
                 final File noBackupFile = new File(mBasePath, name);
                 final File file = new File(
                         mBasePath, name.substring(0, name.length() - SUFFIX_NO_BACKUP.length()));
@@ -116,26 +132,95 @@
     }
 
     /**
-     * Atomically combine data with existing data in currently active file.
-     * Maintains a backup during write, which is restored if the write fails.
+     * Delete all files managed by this rotator.
      */
-    public void combineActive(Reader reader, Writer writer, long currentTimeMillis)
+    public void deleteAll() {
+        final FileInfo info = new FileInfo(mPrefix);
+        for (String name : mBasePath.list()) {
+            if (!info.parse(name)) continue;
+
+            // delete each file that matches parser
+            new File(mBasePath, name).delete();
+        }
+    }
+
+    /**
+     * Process currently active file, first reading any existing data, then
+     * writing modified data. Maintains a backup during write, which is restored
+     * if the write fails.
+     */
+    public void rewriteActive(Rewriter rewriter, long currentTimeMillis)
             throws IOException {
         final String activeName = getActiveName(currentTimeMillis);
+        rewriteSingle(rewriter, activeName);
+    }
 
-        final File file = new File(mBasePath, activeName);
+    @Deprecated
+    public void combineActive(final Reader reader, final Writer writer, long currentTimeMillis)
+            throws IOException {
+        rewriteActive(new Rewriter() {
+            /** {@inheritDoc} */
+            public void reset() {
+                // ignored
+            }
+
+            /** {@inheritDoc} */
+            public void read(InputStream in) throws IOException {
+                reader.read(in);
+            }
+
+            /** {@inheritDoc} */
+            public boolean shouldWrite() {
+                return true;
+            }
+
+            /** {@inheritDoc} */
+            public void write(OutputStream out) throws IOException {
+                writer.write(out);
+            }
+        }, currentTimeMillis);
+    }
+
+    /**
+     * Process all files managed by this rotator, usually to rewrite historical
+     * data. Each file is processed atomically.
+     */
+    public void rewriteAll(Rewriter rewriter) throws IOException {
+        final FileInfo info = new FileInfo(mPrefix);
+        for (String name : mBasePath.list()) {
+            if (!info.parse(name)) continue;
+
+            // process each file that matches parser
+            rewriteSingle(rewriter, name);
+        }
+    }
+
+    /**
+     * Process a single file atomically, first reading any existing data, then
+     * writing modified data. Maintains a backup during write, which is restored
+     * if the write fails.
+     */
+    private void rewriteSingle(Rewriter rewriter, String name) throws IOException {
+        if (LOGD) Slog.d(TAG, "rewriting " + name);
+
+        final File file = new File(mBasePath, name);
         final File backupFile;
 
+        rewriter.reset();
+
         if (file.exists()) {
             // read existing data
-            readFile(file, reader);
+            readFile(file, rewriter);
+
+            // skip when rewriter has nothing to write
+            if (!rewriter.shouldWrite()) return;
 
             // backup existing data during write
-            backupFile = new File(mBasePath, activeName + SUFFIX_BACKUP);
+            backupFile = new File(mBasePath, name + SUFFIX_BACKUP);
             file.renameTo(backupFile);
 
             try {
-                writeFile(file, writer);
+                writeFile(file, rewriter);
 
                 // write success, delete backup
                 backupFile.delete();
@@ -148,11 +233,11 @@
 
         } else {
             // create empty backup during write
-            backupFile = new File(mBasePath, activeName + SUFFIX_NO_BACKUP);
+            backupFile = new File(mBasePath, name + SUFFIX_NO_BACKUP);
             backupFile.createNewFile();
 
             try {
-                writeFile(file, writer);
+                writeFile(file, rewriter);
 
                 // write success, delete empty backup
                 backupFile.delete();
@@ -176,6 +261,8 @@
 
             // read file when it overlaps
             if (info.startMillis <= matchEndMillis && matchStartMillis <= info.endMillis) {
+                if (LOGD) Slog.d(TAG, "reading matching " + name);
+
                 final File file = new File(mBasePath, name);
                 readFile(file, reader);
             }
@@ -224,16 +311,20 @@
             if (!info.parse(name)) continue;
 
             if (info.isActive()) {
-                // found active file; rotate if old enough
-                if (info.startMillis < rotateBefore) {
+                if (info.startMillis <= rotateBefore) {
+                    // found active file; rotate if old enough
+                    if (LOGD) Slog.d(TAG, "rotating " + name);
+
                     info.endMillis = currentTimeMillis;
 
                     final File file = new File(mBasePath, name);
                     final File destFile = new File(mBasePath, info.build());
                     file.renameTo(destFile);
                 }
-            } else if (info.endMillis < deleteBefore) {
+            } else if (info.endMillis <= deleteBefore) {
                 // found rotated file; delete if old enough
+                if (LOGD) Slog.d(TAG, "deleting " + name);
+
                 final File file = new File(mBasePath, name);
                 file.delete();
             }
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
new file mode 100644
index 0000000..3dd2284
--- /dev/null
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * Lightweight wrapper around {@link PrintWriter} that automatically indents
+ * newlines based on internal state. Delays writing indent until first actual
+ * write on a newline, enabling indent modification after newline.
+ */
+public class IndentingPrintWriter extends PrintWriter {
+    private final String mIndent;
+
+    private StringBuilder mBuilder = new StringBuilder();
+    private String mCurrent = new String();
+    private boolean mEmptyLine = true;
+
+    public IndentingPrintWriter(Writer writer, String indent) {
+        super(writer);
+        mIndent = indent;
+    }
+
+    public void increaseIndent() {
+        mBuilder.append(mIndent);
+        mCurrent = mBuilder.toString();
+    }
+
+    public void decreaseIndent() {
+        mBuilder.delete(0, mIndent.length());
+        mCurrent = mBuilder.toString();
+    }
+
+    @Override
+    public void println() {
+        super.println();
+        mEmptyLine = true;
+    }
+
+    @Override
+    public void write(char[] buf, int offset, int count) {
+        if (mEmptyLine) {
+            mEmptyLine = false;
+            super.print(mCurrent);
+        }
+        super.write(buf, offset, count);
+    }
+}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 683aca5..5d80b79 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -67,6 +67,7 @@
     InputMethodSubtype getCurrentInputMethodSubtype();
     boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
     boolean switchToLastInputMethod(in IBinder token);
+    boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme);
     boolean setInputMethodEnabled(String id, boolean enabled);
     oneway void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
 }
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index a235d9a..9024d8d 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -387,9 +387,9 @@
         }
     }
     
-    public boolean deleteSurroundingText(int leftLength, int rightLength) {
+    public boolean deleteSurroundingText(int beforeLength, int afterLength) {
         try {
-            mIInputContext.deleteSurroundingText(leftLength, rightLength);
+            mIInputContext.deleteSurroundingText(beforeLength, afterLength);
             return true;
         } catch (RemoteException e) {
             return false;
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index daefc9a..af3fd42 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -228,7 +228,7 @@
         updateTime();
     }
 
-    private void updateTime() {
+    public void updateTime() {
         mCalendar.setTimeInMillis(System.currentTimeMillis());
 
         CharSequence newTime = DateFormat.format(mFormat, mCalendar);
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 32e733b..9579bce 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -35,6 +35,11 @@
 
     private final TextView mTextView;
 
+    // Keeps track of nested begin/end batch edit to ensure this connection always has a
+    // balanced impact on its associated TextView.
+    // A negative value means that this connection has been finished by the InputMethodManager.
+    private int mBatchEditNesting;
+
     public EditableInputConnection(TextView textview) {
         super(textview, true);
         mTextView = textview;
@@ -48,19 +53,35 @@
         }
         return null;
     }
-    
+
     @Override
     public boolean beginBatchEdit() {
-        mTextView.beginBatchEdit();
-        return true;
+        synchronized(this) {
+            if (mBatchEditNesting >= 0) {
+                mTextView.beginBatchEdit();
+                mBatchEditNesting++;
+                return true;
+            }
+        }
+        return false;
     }
-    
+
     @Override
     public boolean endBatchEdit() {
-        mTextView.endBatchEdit();
-        return true;
+        synchronized(this) {
+            if (mBatchEditNesting > 0) {
+                // When the connection is reset by the InputMethodManager and finishComposingText
+                // is called, some endBatchEdit calls may still be asynchronously received from the
+                // IME. Do not take these into account, thus ensuring that this IC's final
+                // contribution to mTextView's nested batch edit count is zero.
+                mTextView.endBatchEdit();
+                mBatchEditNesting--;
+                return true;
+            }
+        }
+        return false;
     }
-    
+
     @Override
     public boolean clearMetaKeyStates(int states) {
         final Editable content = getEditable();
@@ -76,7 +97,24 @@
         }
         return true;
     }
-    
+
+    @Override
+    public boolean finishComposingText() {
+        final boolean superResult = super.finishComposingText();
+        synchronized(this) {
+            if (mBatchEditNesting < 0) {
+                // The connection was already finished
+                return false;
+            }
+            while (mBatchEditNesting > 0) {
+                endBatchEdit();
+            }
+            // Will prevent any further calls to begin or endBatchEdit
+            mBatchEditNesting = -1;
+        }
+        return superResult;
+    }
+
     @Override
     public boolean commitCompletion(CompletionInfo text) {
         if (DEBUG) Log.v(TAG, "commitCompletion " + text);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 905a171..6893ffb 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -404,7 +404,7 @@
         saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
         setLockPatternEnabled(false);
         saveLockPattern(null);
-        setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+        setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
         setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
     }
 
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index ebd355a..d51ced11 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -653,6 +653,7 @@
 
             case MotionEvent.ACTION_CANCEL:
                 handleMove(event);
+                handleCancel(event);
                 handled = true;
                 break;
         }
@@ -678,6 +679,12 @@
         if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
         switchToState(STATE_FINISH, event.getX(), event.getY());
     }
+    
+    private void handleCancel(MotionEvent event) {
+        if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
+        mActiveTarget = -1; // Drop the active target if canceled.
+        switchToState(STATE_FINISH, event.getX(), event.getY());
+    }
 
     private void handleMove(MotionEvent event) {
         if (!mDragging) {
diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index c4be513..8d57e5d 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -510,13 +510,26 @@
      * @throws MmsException Failed to load some fields of a PDU.
      */
     public GenericPdu load(Uri uri) throws MmsException {
-        PduCacheEntry cacheEntry = PDU_CACHE_INSTANCE.get(uri);
-        if (cacheEntry != null) {
-            return cacheEntry.getPdu();
+        PduCacheEntry cacheEntry;
+        synchronized(PDU_CACHE_INSTANCE) {
+            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
+                try {
+                    PDU_CACHE_INSTANCE.wait();
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "load: ", e);
+                }
+                cacheEntry = PDU_CACHE_INSTANCE.get(uri);
+                if (cacheEntry != null) {
+                    return cacheEntry.getPdu();
+                }
+            }
+            // Tell the cache to indicate to other callers that this item
+            // is currently being updated.
+            PDU_CACHE_INSTANCE.setUpdating(uri, true);
         }
 
         Cursor c = SqliteWrapper.query(mContext, mContentResolver, uri,
-                        PDU_PROJECTION, null, null, null);
+                                                PDU_PROJECTION, null, null, null);
         PduHeaders headers = new PduHeaders();
         Set<Entry<Integer, Integer>> set;
         long msgId = ContentUris.parseId(uri);
@@ -634,9 +647,14 @@
                         "Unrecognized PDU type: " + Integer.toHexString(msgType));
         }
 
-        cacheEntry = new PduCacheEntry(pdu, msgBox, threadId);
-        PDU_CACHE_INSTANCE.put(uri, cacheEntry);
-        return pdu;
+        synchronized(PDU_CACHE_INSTANCE ) {
+            assert(PDU_CACHE_INSTANCE.get(uri) == null);
+            // Update the cache entry with the real info
+            cacheEntry = new PduCacheEntry(pdu, msgBox, threadId);
+            PDU_CACHE_INSTANCE.put(uri, cacheEntry);
+            PDU_CACHE_INSTANCE.notifyAll();     // tell anybody waiting on this entry to go ahead
+            return pdu;
+        }
     }
 
     private void persistAddress(
@@ -818,6 +836,17 @@
      * @throws MmsException Bad URI or updating failed.
      */
     public void updateHeaders(Uri uri, SendReq sendReq) {
+        synchronized(PDU_CACHE_INSTANCE) {
+            // If the cache item is getting updated, wait until it's done updating before
+            // purging it.
+            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
+                try {
+                    PDU_CACHE_INSTANCE.wait();
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "updateHeaders: ", e);
+                }
+            }
+        }
         PDU_CACHE_INSTANCE.purge(uri);
 
         ContentValues values = new ContentValues(10);
@@ -969,52 +998,72 @@
      */
     public void updateParts(Uri uri, PduBody body)
             throws MmsException {
-        PduCacheEntry cacheEntry = PDU_CACHE_INSTANCE.get(uri);
-        if (cacheEntry != null) {
-            ((MultimediaMessagePdu) cacheEntry.getPdu()).setBody(body);
-        }
-
-        ArrayList<PduPart> toBeCreated = new ArrayList<PduPart>();
-        HashMap<Uri, PduPart> toBeUpdated = new HashMap<Uri, PduPart>();
-
-        int partsNum = body.getPartsNum();
-        StringBuilder filter = new StringBuilder().append('(');
-        for (int i = 0; i < partsNum; i++) {
-            PduPart part = body.getPart(i);
-            Uri partUri = part.getDataUri();
-            if ((partUri == null) || !partUri.getAuthority().startsWith("mms")) {
-                toBeCreated.add(part);
-            } else {
-                toBeUpdated.put(partUri, part);
-
-                // Don't use 'i > 0' to determine whether we should append
-                // 'AND' since 'i = 0' may be skipped in another branch.
-                if (filter.length() > 1) {
-                    filter.append(" AND ");
+        try {
+            PduCacheEntry cacheEntry;
+            synchronized(PDU_CACHE_INSTANCE) {
+                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
+                    try {
+                        PDU_CACHE_INSTANCE.wait();
+                    } catch (InterruptedException e) {
+                        Log.e(TAG, "updateParts: ", e);
+                    }
+                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);
+                    if (cacheEntry != null) {
+                        ((MultimediaMessagePdu) cacheEntry.getPdu()).setBody(body);
+                    }
                 }
-
-                filter.append(Part._ID);
-                filter.append("!=");
-                DatabaseUtils.appendEscapedSQLString(filter, partUri.getLastPathSegment());
+                // Tell the cache to indicate to other callers that this item
+                // is currently being updated.
+                PDU_CACHE_INSTANCE.setUpdating(uri, true);
             }
-        }
-        filter.append(')');
 
-        long msgId = ContentUris.parseId(uri);
+            ArrayList<PduPart> toBeCreated = new ArrayList<PduPart>();
+            HashMap<Uri, PduPart> toBeUpdated = new HashMap<Uri, PduPart>();
 
-        // Remove the parts which doesn't exist anymore.
-        SqliteWrapper.delete(mContext, mContentResolver,
-                Uri.parse(Mms.CONTENT_URI + "/" + msgId + "/part"),
-                filter.length() > 2 ? filter.toString() : null, null);
+            int partsNum = body.getPartsNum();
+            StringBuilder filter = new StringBuilder().append('(');
+            for (int i = 0; i < partsNum; i++) {
+                PduPart part = body.getPart(i);
+                Uri partUri = part.getDataUri();
+                if ((partUri == null) || !partUri.getAuthority().startsWith("mms")) {
+                    toBeCreated.add(part);
+                } else {
+                    toBeUpdated.put(partUri, part);
 
-        // Create new parts which didn't exist before.
-        for (PduPart part : toBeCreated) {
-            persistPart(part, msgId);
-        }
+                    // Don't use 'i > 0' to determine whether we should append
+                    // 'AND' since 'i = 0' may be skipped in another branch.
+                    if (filter.length() > 1) {
+                        filter.append(" AND ");
+                    }
 
-        // Update the modified parts.
-        for (Map.Entry<Uri, PduPart> e : toBeUpdated.entrySet()) {
-            updatePart(e.getKey(), e.getValue());
+                    filter.append(Part._ID);
+                    filter.append("!=");
+                    DatabaseUtils.appendEscapedSQLString(filter, partUri.getLastPathSegment());
+                }
+            }
+            filter.append(')');
+
+            long msgId = ContentUris.parseId(uri);
+
+            // Remove the parts which doesn't exist anymore.
+            SqliteWrapper.delete(mContext, mContentResolver,
+                    Uri.parse(Mms.CONTENT_URI + "/" + msgId + "/part"),
+                    filter.length() > 2 ? filter.toString() : null, null);
+
+            // Create new parts which didn't exist before.
+            for (PduPart part : toBeCreated) {
+                persistPart(part, msgId);
+            }
+
+            // Update the modified parts.
+            for (Map.Entry<Uri, PduPart> e : toBeUpdated.entrySet()) {
+                updatePart(e.getKey(), e.getValue());
+            }
+        } finally {
+            synchronized(PDU_CACHE_INSTANCE) {
+                PDU_CACHE_INSTANCE.setUpdating(uri, false);
+                PDU_CACHE_INSTANCE.notifyAll();
+            }
         }
     }
 
@@ -1029,15 +1078,32 @@
         if (uri == null) {
             throw new MmsException("Uri may not be null.");
         }
+        long msgId = -1;
+        try {
+            msgId = ContentUris.parseId(uri);
+        } catch (NumberFormatException e) {
+            // the uri ends with "inbox" or something else like that
+        }
+        boolean existingUri = msgId != -1;
 
-        Integer msgBox = MESSAGE_BOX_MAP.get(uri);
-        if (msgBox == null) {
+        if (!existingUri && MESSAGE_BOX_MAP.get(uri) == null) {
             throw new MmsException(
                     "Bad destination, must be one of "
                     + "content://mms/inbox, content://mms/sent, "
                     + "content://mms/drafts, content://mms/outbox, "
                     + "content://mms/temp.");
         }
+        synchronized(PDU_CACHE_INSTANCE) {
+            // If the cache item is getting updated, wait until it's done updating before
+            // purging it.
+            if (PDU_CACHE_INSTANCE.isUpdating(uri)) {
+                try {
+                    PDU_CACHE_INSTANCE.wait();
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "persist1: ", e);
+                }
+            }
+        }
         PDU_CACHE_INSTANCE.purge(uri);
 
         PduHeaders header = pdu.getPduHeaders();
@@ -1145,14 +1211,20 @@
             }
         }
 
-        Uri res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
-        if (res == null) {
-            throw new MmsException("persist() failed: return null.");
+        Uri res = null;
+        if (existingUri) {
+            res = uri;
+            SqliteWrapper.update(mContext, mContentResolver, res, values, null, null);
+        } else {
+            res = SqliteWrapper.insert(mContext, mContentResolver, uri, values);
+            if (res == null) {
+                throw new MmsException("persist() failed: return null.");
+            }
+            // Get the real ID of the PDU and update all parts which were
+            // saved with the dummy ID.
+            msgId = ContentUris.parseId(res);
         }
 
-        // Get the real ID of the PDU and update all parts which were
-        // saved with the dummy ID.
-        long msgId = ContentUris.parseId(res);
         values = new ContentValues(1);
         values.put(Part.MSG_ID, msgId);
         SqliteWrapper.update(mContext, mContentResolver,
@@ -1163,7 +1235,9 @@
         // persisted PDU is '8', we should return "content://mms/inbox/8"
         // instead of "content://mms/8".
         // FIXME: Should the MmsProvider be responsible for this???
-        res = Uri.parse(uri + "/" + msgId);
+        if (!existingUri) {
+            res = Uri.parse(uri + "/" + msgId);
+        }
 
         // Save address information.
         for (int addrType : ADDRESS_FIELDS) {
diff --git a/core/java/com/google/android/mms/util/PduCache.java b/core/java/com/google/android/mms/util/PduCache.java
index 059af72..87cb48e 100644
--- a/core/java/com/google/android/mms/util/PduCache.java
+++ b/core/java/com/google/android/mms/util/PduCache.java
@@ -73,10 +73,12 @@
 
     private final HashMap<Integer, HashSet<Uri>> mMessageBoxes;
     private final HashMap<Long, HashSet<Uri>> mThreads;
+    private final HashSet<Uri> mUpdating;
 
     private PduCache() {
         mMessageBoxes = new HashMap<Integer, HashSet<Uri>>();
         mThreads = new HashMap<Long, HashSet<Uri>>();
+        mUpdating = new HashSet<Uri>();
     }
 
     synchronized public static final PduCache getInstance() {
@@ -111,9 +113,22 @@
             msgBox.add(finalKey);
             thread.add(finalKey);
         }
+        setUpdating(uri, false);
         return result;
     }
 
+    synchronized public void setUpdating(Uri uri, boolean updating) {
+        if (updating) {
+            mUpdating.add(uri);
+        } else {
+            mUpdating.remove(uri);
+        }
+    }
+
+    synchronized public boolean isUpdating(Uri uri) {
+        return mUpdating.contains(uri);
+    }
+
     @Override
     synchronized public PduCacheEntry purge(Uri uri) {
         int match = URI_MATCHER.match(uri);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 39b84bb..78e8df3 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -126,6 +126,7 @@
 	android_media_ToneGenerator.cpp \
 	android_hardware_Camera.cpp \
 	android_hardware_SensorManager.cpp \
+	android_hardware_SerialPort.cpp \
 	android_hardware_UsbDevice.cpp \
 	android_hardware_UsbDeviceConnection.cpp \
 	android_hardware_UsbRequest.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8a3063f..3067e75 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -76,6 +76,7 @@
 
 extern int register_android_hardware_Camera(JNIEnv *env);
 extern int register_android_hardware_SensorManager(JNIEnv *env);
+extern int register_android_hardware_SerialPort(JNIEnv *env);
 extern int register_android_hardware_UsbDevice(JNIEnv *env);
 extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
 extern int register_android_hardware_UsbRequest(JNIEnv *env);
@@ -1157,6 +1158,7 @@
     REG_JNI(register_com_android_internal_os_ZygoteInit),
     REG_JNI(register_android_hardware_Camera),
     REG_JNI(register_android_hardware_SensorManager),
+    REG_JNI(register_android_hardware_SerialPort),
     REG_JNI(register_android_hardware_UsbDevice),
     REG_JNI(register_android_hardware_UsbDeviceConnection),
     REG_JNI(register_android_hardware_UsbRequest),
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index c8b725a..ef6af74 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -67,7 +67,7 @@
     static void freeCaches(JNIEnv* env, jobject) {
         // these are called in no particular order
         SkImageRef_GlobalPool::SetRAMUsed(0);
-        SkGraphics::SetFontCacheUsed(0);
+        SkGraphics::PurgeFontCache();
     }
     
     static jboolean isOpaque(JNIEnv* env, jobject jcanvas) {
@@ -757,20 +757,11 @@
             int start, int count, int contextCount,
             jfloat x, jfloat y, int flags, SkPaint* paint) {
 
-        sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-        value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count,
-                contextCount, flags);
+        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+                textArray, start, count, contextCount, flags);
         if (value == NULL) {
-            ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                    String8(textArray + start, count).string());
-            return ;
+            return;
         }
-#else
-        value = new TextLayoutCacheValue(contextCount);
-        TextLayoutEngine::getInstance().computeValues(value.get(), paint,
-                reinterpret_cast<const UChar*>(textArray), start, count, contextCount, flags);
-#endif
         doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint);
     }
 
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 47ffd94..a1d41ee 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -518,12 +518,6 @@
 bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
     JNIEnv* env = vm2env(fVM);
 
-    // If allocating in the Java heap, only allow a single object to be
-    // allocated for the lifetime of this object.
-    if (fStorageObj != NULL) {
-        SkDebugf("WARNING: One-shot allocator has already allocated (alloc count = %d)\n", fAllocCount);
-//        sk_throw();
-    }
     fStorageObj = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
     fAllocCount += 1;
     return fStorageObj != NULL;
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 9bcfa5f..376c841 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -465,11 +465,10 @@
 
         jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
 
-        TextLayoutCacheValue value(contextCount);
-        TextLayoutEngine::getInstance().computeValues(&value, paint, text, start, count,
-                contextCount, flags);
-        const jchar* shapedGlyphs = value.getGlyphs();
-        size_t glyphsCount = value.getGlyphsCount();
+        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+                text, start, count, contextCount, flags);
+        const jchar* shapedGlyphs = value->getGlyphs();
+        size_t glyphsCount = value->getGlyphsCount();
         memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount);
 
         env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
@@ -677,20 +676,11 @@
     static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
                          int count, float maxWidth, jfloatArray jmeasured,
                          SkPaint::TextBufferDirection tbd) {
-        sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-        value = TextLayoutCache::getInstance().getValue(&paint, text, 0, count,
-                count, paint.getFlags());
+        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
+                text, 0, count, count, paint.getFlags());
         if (value == NULL) {
-            ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                    String8(text, count).string());
+            return 0;
         }
-#else
-        value = new TextLayoutCacheValue(count);
-        TextLayoutEngine::getInstance().computeValues(value.get(), &paint,
-                reinterpret_cast<const UChar*>(text), 0, count, count, paint.getFlags());
-#endif
-
         SkScalar     measured;
         size_t       bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1,
                                    SkFloatToScalar(maxWidth), &measured, tbd);
@@ -756,19 +746,11 @@
         SkRect  r;
         SkIRect ir;
 
-        sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-        value = TextLayoutCache::getInstance().getValue(&paint, text, 0, count,
-                count, paint.getFlags());
+        sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
+                text, 0, count, count, paint.getFlags());
         if (value == NULL) {
-            ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                    String8(text, count).string());
+            return;
         }
-#else
-        value = new TextLayoutCacheValue(count);
-        TextLayoutEngine::getInstance().computeValues(value.get(), &paint,
-                reinterpret_cast<const UChar*>(text), 0, count, count, paint.getFlags());
-#endif
         paint.measureText(value->getGlyphs(), value->getGlyphsCount() << 1, &r);
         r.roundOut(&ir);
         GraphicsJNI::irect_to_jrect(ir, env, bounds);
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index 2d83851..2241f60 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -53,19 +53,9 @@
 // a path representing the text that would have been drawn.
 void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
                             jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
-    sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-    // Return advances from the cache. Compute them if needed
-    value = TextLayoutCache::getInstance().getValue(paint, text, 0, len,
-            len, bidiFlags);
-#else
-    value = new TextLayoutCacheValue(len);
-    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
-            reinterpret_cast<const UChar*>(text), 0, len, len, bidiFlags);
-#endif
+    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+            text, 0, len, len, bidiFlags);
     if (value == NULL) {
-        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                String8(text, len).string());
         return ;
     }
     SkScalar x_ = SkFloatToScalar(x);
@@ -77,19 +67,9 @@
 void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
                                     jint count, jint contextCount, jint dirFlags,
                                     jfloat* resultAdvances, jfloat* resultTotalAdvance) {
-    sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-    // Return advances from the cache. Compute them if needed
-    value = TextLayoutCache::getInstance().getValue(paint, chars, start, count,
-            contextCount, dirFlags);
-#else
-    value = new TextLayoutCacheValue(contextCount);
-    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
-            reinterpret_cast<const UChar*>(chars), start, count, contextCount, dirFlags);
-#endif
+    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+            chars, start, count, contextCount, dirFlags);
     if (value == NULL) {
-        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                String8(chars + start, count).string());
         return ;
     }
     if (resultAdvances) {
@@ -126,20 +106,12 @@
         return;
     }
 
-    sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-    value = TextLayoutCache::getInstance().getValue(paint, text, 0, count,
-            count, bidiFlags);
-#else
-    value = new TextLayoutCacheValue(count);
-    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
-            reinterpret_cast<const UChar*>(text), 0, count, count, bidiFlags);
-#endif
+    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+            text, 0, count, count, bidiFlags);
     if (value == NULL) {
-        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                String8(text, count).string());
-        return ;
+        return;
     }
+
     // Beware: this needs Glyph encoding (already done on the Paint constructor)
     canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
 }
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 71c283a..7f5d54d 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -29,24 +29,24 @@
 namespace android {
 
 //--------------------------------------------------------------------------------------------------
-#define TYPEFACE_ARABIC "/system/fonts/DroidNaskh-Regular.ttf"
+// Using DroidSansArabic for shaping Arabic with Harfbuzz because its metrics are more compatible
+// with the "Roboto" metrics (compared to DroidNaskh-Regular). When we will have an Arabic font
+// whose metrics are similar to the Roboto ones, then we will need to use it for shaping.
+#define TYPEFACE_ARABIC "/system/fonts/DroidSansArabic.ttf"
 #define TYPE_FACE_HEBREW_REGULAR "/system/fonts/DroidSansHebrew-Regular.ttf"
 #define TYPE_FACE_HEBREW_BOLD "/system/fonts/DroidSansHebrew-Bold.ttf"
 #define TYPEFACE_BENGALI "/system/fonts/Lohit-Bengali.ttf"
 #define TYPEFACE_THAI "/system/fonts/DroidSansThai.ttf"
 
-#if USE_TEXT_LAYOUT_CACHE
+ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
 
-    ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutCache);
-
-#endif
-
-    ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
+static KeyedVector<UChar, UChar> gBidiMirrored;
 
 //--------------------------------------------------------------------------------------------------
 
-TextLayoutCache::TextLayoutCache() :
-        mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> >::kUnlimitedCapacity),
+TextLayoutCache::TextLayoutCache(TextLayoutShaper* shaper) :
+        mShaper(shaper),
+        mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> >::kUnlimitedCapacity),
         mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)),
         mCacheHitCount(0), mNanosecondsSaved(0) {
     init();
@@ -75,7 +75,7 @@
 /**
  *  Callbacks
  */
-void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc) {
+void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc) {
     size_t totalSizeToDelete = text.getSize() + desc->getSize();
     mSize -= totalSizeToDelete;
     if (mDebugEnabled) {
@@ -93,7 +93,7 @@
 /*
  * Caching
  */
-sp<TextLayoutCacheValue> TextLayoutCache::getValue(const SkPaint* paint,
+sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
             const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
     AutoMutex _l(mLock);
     nsecs_t startTime = 0;
@@ -105,7 +105,7 @@
     TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
 
     // Get value from cache if possible
-    sp<TextLayoutCacheValue> value = mCache.get(key);
+    sp<TextLayoutValue> value = mCache.get(key);
 
     // Value not found for the key, we need to add a new value in the cache
     if (value == NULL) {
@@ -113,10 +113,10 @@
             startTime = systemTime(SYSTEM_TIME_MONOTONIC);
         }
 
-        value = new TextLayoutCacheValue(contextCount);
+        value = new TextLayoutValue(contextCount);
 
         // Compute advances and store them
-        TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+        mShaper->computeValues(value.get(), paint,
                 reinterpret_cast<const UChar*>(text), start, count,
                 size_t(contextCount), int(dirFlags));
 
@@ -312,31 +312,33 @@
 /**
  * TextLayoutCacheValue
  */
-TextLayoutCacheValue::TextLayoutCacheValue(size_t contextCount) :
+TextLayoutValue::TextLayoutValue(size_t contextCount) :
         mTotalAdvance(0), mElapsedTime(0) {
     // Give a hint for advances and glyphs vectors size
     mAdvances.setCapacity(contextCount);
     mGlyphs.setCapacity(contextCount);
 }
 
-size_t TextLayoutCacheValue::getSize() const {
-    return sizeof(TextLayoutCacheValue) + sizeof(jfloat) * mAdvances.capacity() +
+size_t TextLayoutValue::getSize() const {
+    return sizeof(TextLayoutValue) + sizeof(jfloat) * mAdvances.capacity() +
             sizeof(jchar) * mGlyphs.capacity();
 }
 
-void TextLayoutCacheValue::setElapsedTime(uint32_t time) {
+void TextLayoutValue::setElapsedTime(uint32_t time) {
     mElapsedTime = time;
 }
 
-uint32_t TextLayoutCacheValue::getElapsedTime() {
+uint32_t TextLayoutValue::getElapsedTime() {
     return mElapsedTime;
 }
 
-TextLayoutEngine::TextLayoutEngine() : mShaperItemGlyphArraySize(0) {
+TextLayoutShaper::TextLayoutShaper() : mShaperItemGlyphArraySize(0) {
     mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal);
     mArabicTypeface = NULL;
     mHebrewRegularTypeface = NULL;
     mHebrewBoldTypeface = NULL;
+    mBengaliTypeface = NULL;
+    mThaiTypeface = NULL;
 
     mFontRec.klass = &harfbuzzSkiaClass;
     mFontRec.userData = 0;
@@ -353,14 +355,36 @@
 
     mShaperItem.font = &mFontRec;
     mShaperItem.font->userData = &mShapingPaint;
+
+    // Fill the BiDi mirrored chars map
+    // See: http://www.unicode.org/Public/6.0.0/ucd/extracted/DerivedBinaryProperties.txt
+    gBidiMirrored.add('(', ')');
+    gBidiMirrored.add(')', '(');
+    gBidiMirrored.add('[', ']');
+    gBidiMirrored.add(']', '[');
+    gBidiMirrored.add('{', '}');
+    gBidiMirrored.add('}', '{');
+    gBidiMirrored.add('<', '>');
+    gBidiMirrored.add('>', '<');
+    gBidiMirrored.add(0x00ab, 0x00bb); // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+    gBidiMirrored.add(0x00bb, 0x00ab); // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+    gBidiMirrored.add(0x2039, 0x203a); // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+    gBidiMirrored.add(0x203a, 0x2039); // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+    gBidiMirrored.add(0x2264, 0x2265); // LESS-THAN OR EQUAL TO
+    gBidiMirrored.add(0x2265, 0x2264); // GREATER-THAN OR EQUAL TO
 }
 
-TextLayoutEngine::~TextLayoutEngine() {
-    // FIXME should free fonts and caches but since this class is a singleton,
-    // we don't bother at the moment
+TextLayoutShaper::~TextLayoutShaper() {
+    SkSafeUnref(mDefaultTypeface);
+    SkSafeUnref(mArabicTypeface);
+    SkSafeUnref(mHebrewRegularTypeface);
+    SkSafeUnref(mHebrewBoldTypeface);
+    SkSafeUnref(mBengaliTypeface);
+    SkSafeUnref(mThaiTypeface);
+    deleteShaperItemGlyphArrays();
 }
 
-void TextLayoutEngine::computeValues(TextLayoutCacheValue* value, const SkPaint* paint, const UChar* chars,
+void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
         size_t start, size_t count, size_t contextCount, int dirFlags) {
 
     computeValues(paint, chars, start, count, contextCount, dirFlags,
@@ -371,7 +395,7 @@
 #endif
 }
 
-void TextLayoutEngine::computeValues(const SkPaint* paint, const UChar* chars,
+void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
         size_t start, size_t count, size_t contextCount, int dirFlags,
         Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
         Vector<jchar>* const outGlyphs) {
@@ -513,7 +537,7 @@
     }
 }
 
-void TextLayoutEngine::computeRunValues(const SkPaint* paint, const UChar* chars,
+void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars,
         size_t count, bool isRTL,
         Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
         Vector<jchar>* const outGlyphs) {
@@ -575,6 +599,31 @@
         }
     }
 
+    // Reverse "BiDi mirrored chars" in RTL mode only
+    // See: http://www.unicode.org/Public/6.0.0/ucd/extracted/DerivedBinaryProperties.txt
+    // This is a workaround because Harfbuzz is not able to do mirroring in all cases and
+    // script-run splitting with Harfbuzz is splitting on parenthesis
+    if (isRTL) {
+        for (ssize_t i = 0; i < ssize_t(count); i++) {
+            UChar ch = chars[i];
+            ssize_t index = gBidiMirrored.indexOfKey(ch);
+            // Skip non "BiDi mirrored" chars
+            if (index < 0) {
+                continue;
+            }
+            if (!useNormalizedString) {
+                useNormalizedString = true;
+                mNormalizedString.setTo(false /* not terminated*/, chars, count);
+            }
+            UChar result = gBidiMirrored.valueAt(index);
+            mNormalizedString.setCharAt(i, result);
+#if DEBUG_GLYPHS
+            ALOGD("Rewriting codepoint '%d' to '%d' at position %d",
+                    ch, mNormalizedString[i], int(i));
+#endif
+        }
+    }
+
 #if DEBUG_GLYPHS
     if (useNormalizedString) {
         ALOGD("Will use normalized string '%s', length = %d",
@@ -719,7 +768,7 @@
 }
 
 
-size_t TextLayoutEngine::shapeFontRun(const SkPaint* paint, bool isRTL) {
+size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint, bool isRTL) {
     // Reset kerning
     mShaperItem.kerning_applied = false;
 
@@ -811,7 +860,7 @@
     case HB_Script_Hebrew:
     case HB_Script_Bengali:
     case HB_Script_Thai:{
-        const uint16_t* text16 = (const uint16_t*)mShaperItem.string;
+        const uint16_t* text16 = (const uint16_t*)(mShaperItem.string + mShaperItem.item.pos);
         SkUnichar firstUnichar = SkUTF16_NextUnichar(&text16);
         baseGlyphCount = paint->getBaseGlyphCount(firstUnichar);
         break;
@@ -833,14 +882,14 @@
     return baseGlyphCount;
 }
 
-void TextLayoutEngine::ensureShaperItemGlyphArrays(size_t size) {
+void TextLayoutShaper::ensureShaperItemGlyphArrays(size_t size) {
     if (size > mShaperItemGlyphArraySize) {
         deleteShaperItemGlyphArrays();
         createShaperItemGlyphArrays(size);
     }
 }
 
-void TextLayoutEngine::createShaperItemGlyphArrays(size_t size) {
+void TextLayoutShaper::createShaperItemGlyphArrays(size_t size) {
 #if DEBUG_GLYPHS
     ALOGD("Creating Glyph Arrays with size = %d", size);
 #endif
@@ -858,7 +907,7 @@
     mShaperItem.log_clusters = new unsigned short[size];
 }
 
-void TextLayoutEngine::deleteShaperItemGlyphArrays() {
+void TextLayoutShaper::deleteShaperItemGlyphArrays() {
     delete[] mShaperItem.glyphs;
     delete[] mShaperItem.attributes;
     delete[] mShaperItem.advances;
@@ -866,7 +915,7 @@
     delete[] mShaperItem.log_clusters;
 }
 
-SkTypeface* TextLayoutEngine::getCachedTypeface(SkTypeface** typeface, const char path[]) {
+SkTypeface* TextLayoutShaper::getCachedTypeface(SkTypeface** typeface, const char path[]) {
     if (!*typeface) {
         *typeface = SkTypeface::CreateFromFile(path);
         // CreateFromFile(path) can return NULL if the path is non existing
@@ -884,7 +933,7 @@
     return *typeface;
 }
 
-HB_Face TextLayoutEngine::getCachedHBFace(SkTypeface* typeface) {
+HB_Face TextLayoutShaper::getCachedHBFace(SkTypeface* typeface) {
     SkFontID fontId = typeface->uniqueID();
     ssize_t index = mCachedHBFaces.indexOfKey(fontId);
     if (index >= 0) {
@@ -900,4 +949,36 @@
     return face;
 }
 
+TextLayoutEngine::TextLayoutEngine() {
+    mShaper = new TextLayoutShaper();
+#if USE_TEXT_LAYOUT_CACHE
+    mTextLayoutCache = new TextLayoutCache(mShaper);
+#else
+    mTextLayoutCache = NULL;
+#endif
+}
+
+TextLayoutEngine::~TextLayoutEngine() {
+    delete mTextLayoutCache;
+    delete mShaper;
+}
+
+sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
+        jint start, jint count, jint contextCount, jint dirFlags) {
+    sp<TextLayoutValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+    value = mTextLayoutCache->getValue(paint, text, start, count,
+            contextCount, dirFlags);
+    if (value == NULL) {
+        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
+                String8(text + start, count).string());
+    }
+#else
+    value = new TextLayoutValue(count);
+    mShaper->computeValues(value.get(), paint,
+            reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
+#endif
+    return value;
+}
+
 } // namespace android
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 956e8ca..7ac2f18 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -115,11 +115,11 @@
 }
 
 /*
- * TextLayoutCacheValue is the Cache value
+ * TextLayoutValue is the Cache value
  */
-class TextLayoutCacheValue : public RefBase {
+class TextLayoutValue : public RefBase {
 public:
-    TextLayoutCacheValue(size_t contextCount);
+    TextLayoutValue(size_t contextCount);
 
     void setElapsedTime(uint32_t time);
     uint32_t getElapsedTime();
@@ -159,72 +159,14 @@
 }; // TextLayoutCacheValue
 
 /**
- * Cache of text layout information.
+ * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library)
  */
-class TextLayoutCache : public OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutCacheValue> >,
-        public Singleton<TextLayoutCache>
-{
+class TextLayoutShaper {
 public:
-    TextLayoutCache();
+    TextLayoutShaper();
+    virtual ~TextLayoutShaper();
 
-    virtual ~TextLayoutCache();
-
-    bool isInitialized() {
-        return mInitialized;
-    }
-
-    /**
-     * Used as a callback when an entry is removed from the cache
-     * Do not invoke directly
-     */
-    void operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc);
-
-    sp<TextLayoutCacheValue> getValue(const SkPaint* paint, const jchar* text, jint start, jint count,
-            jint contextCount, jint dirFlags);
-
-    /**
-     * Clear the cache
-     */
-    void clear();
-
-private:
-    Mutex mLock;
-    bool mInitialized;
-
-    GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> > mCache;
-
-    uint32_t mSize;
-    uint32_t mMaxSize;
-
-    uint32_t mCacheHitCount;
-    uint64_t mNanosecondsSaved;
-
-    uint64_t mCacheStartTime;
-
-    RtlDebugLevel mDebugLevel;
-    bool mDebugEnabled;
-
-    /*
-     * Class initialization
-     */
-    void init();
-
-    /**
-     * Dump Cache statistics
-     */
-    void dumpCacheStats();
-
-}; // TextLayoutCache
-
-/**
- * The TextLayoutEngine is responsible for shaping with Harfbuzz library
- */
-class TextLayoutEngine : public Singleton<TextLayoutEngine> {
-public:
-    TextLayoutEngine();
-    virtual ~TextLayoutEngine();
-
-    void computeValues(TextLayoutCacheValue* value, const SkPaint* paint, const UChar* chars,
+    void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
             size_t start, size_t count, size_t contextCount, int dirFlags);
 
 private:
@@ -292,8 +234,80 @@
     void createShaperItemGlyphArrays(size_t size);
     void deleteShaperItemGlyphArrays();
 
-}; // TextLayoutEngine
+}; // TextLayoutShaper
 
+/**
+ * Cache of text layout information.
+ */
+class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
+{
+public:
+    TextLayoutCache(TextLayoutShaper* shaper);
+
+    ~TextLayoutCache();
+
+    bool isInitialized() {
+        return mInitialized;
+    }
+
+    /**
+     * Used as a callback when an entry is removed from the cache
+     * Do not invoke directly
+     */
+    void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
+
+    sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
+            jint count, jint contextCount, jint dirFlags);
+
+    /**
+     * Clear the cache
+     */
+    void clear();
+
+private:
+    TextLayoutShaper* mShaper;
+    Mutex mLock;
+    bool mInitialized;
+
+    GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
+
+    uint32_t mSize;
+    uint32_t mMaxSize;
+
+    uint32_t mCacheHitCount;
+    uint64_t mNanosecondsSaved;
+
+    uint64_t mCacheStartTime;
+
+    RtlDebugLevel mDebugLevel;
+    bool mDebugEnabled;
+
+    /*
+     * Class initialization
+     */
+    void init();
+
+    /**
+     * Dump Cache statistics
+     */
+    void dumpCacheStats();
+
+}; // TextLayoutCache
+
+/**
+ * The TextLayoutEngine is reponsible for computing TextLayoutValues
+ */
+class TextLayoutEngine : public Singleton<TextLayoutEngine> {
+public:
+    TextLayoutEngine();
+    virtual ~TextLayoutEngine();
+
+    sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
+            jint count, jint contextCount, jint dirFlags);
+private:
+    TextLayoutCache* mTextLayoutCache;
+    TextLayoutShaper* mShaper;
+}; // TextLayoutEngine
 
 } // namespace android
 #endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index ac4fe5b..536681b 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -130,21 +130,21 @@
 void AInputQueue::attachLooper(ALooper* looper, int ident,
         ALooper_callbackFunc callback, void* data) {
     mLooper = static_cast<android::Looper*>(looper);
-    mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(),
+    mLooper->addFd(mConsumer.getChannel()->getFd(),
             ident, ALOOPER_EVENT_INPUT, callback, data);
     mLooper->addFd(mDispatchKeyRead,
             ident, ALOOPER_EVENT_INPUT, callback, data);
 }
 
 void AInputQueue::detachLooper() {
-    mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd());
+    mLooper->removeFd(mConsumer.getChannel()->getFd());
     mLooper->removeFd(mDispatchKeyRead);
 }
 
 int32_t AInputQueue::hasEvents() {
     struct pollfd pfd[2];
 
-    pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd();
+    pfd[0].fd = mConsumer.getChannel()->getFd();
     pfd[0].events = POLLIN;
     pfd[0].revents = 0;
     pfd[1].fd = mDispatchKeyRead;
@@ -172,7 +172,7 @@
             in_flight_event inflight;
             inflight.event = kevent;
             inflight.seq = -1;
-            inflight.doFinish = false;
+            inflight.finishSeq = 0;
             mInFlightEvents.push(inflight);
         }
         if (mFinishPreDispatches.size() > 0) {
@@ -200,27 +200,22 @@
             return 0;
         }
     }
-    
-    int32_t res = mConsumer.receiveDispatchSignal();
-    if (res != android::OK) {
-        ALOGE("channel '%s' ~ Failed to receive dispatch signal.  status=%d",
-                mConsumer.getChannel()->getName().string(), res);
-        return -1;
-    }
 
+    uint32_t consumerSeq;
     InputEvent* myEvent = NULL;
-    res = mConsumer.consume(this, &myEvent);
+    status_t res = mConsumer.consume(this, true /*consumeBatches*/, &consumerSeq, &myEvent);
     if (res != android::OK) {
-        ALOGW("channel '%s' ~ Failed to consume input event.  status=%d",
-                mConsumer.getChannel()->getName().string(), res);
-        mConsumer.sendFinishedSignal(false);
+        if (res != android::WOULD_BLOCK) {
+            ALOGW("channel '%s' ~ Failed to consume input event.  status=%d",
+                    mConsumer.getChannel()->getName().string(), res);
+        }
         return -1;
     }
 
     in_flight_event inflight;
     inflight.event = myEvent;
     inflight.seq = -1;
-    inflight.doFinish = true;
+    inflight.finishSeq = consumerSeq;
     mInFlightEvents.push(inflight);
 
     *outEvent = myEvent;
@@ -262,8 +257,8 @@
     for (size_t i=0; i<N; i++) {
         const in_flight_event& inflight(mInFlightEvents[i]);
         if (inflight.event == event) {
-            if (inflight.doFinish) {
-                int32_t res = mConsumer.sendFinishedSignal(handled);
+            if (inflight.finishSeq) {
+                status_t res = mConsumer.sendFinishedSignal(inflight.finishSeq, handled);
                 if (res != android::OK) {
                     ALOGW("Failed to send finished signal on channel '%s'.  status=%d",
                             mConsumer.getChannel()->getName().string(), res);
@@ -481,11 +476,6 @@
                     android_view_InputChannel_getInputChannel(env, _channel);
             if (ic != NULL) {
                 nativeInputQueue = new AInputQueue(ic, mainWorkWrite);
-                if (nativeInputQueue->getConsumer().initialize() != android::OK) {
-                    delete nativeInputQueue;
-                    nativeInputQueue = NULL;
-                    return UNKNOWN_ERROR;
-                }
             } else {
                 return UNKNOWN_ERROR;
             }
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index f4b5dca..abe0104 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -52,7 +52,6 @@
     if (keyUTF == NULL) {
         return -1;
     }
-
     err = writer->WriteEntityHeader(String8(keyUTF), dataSize);
 
     env->ReleaseStringUTFChars(key, keyUTF);
diff --git a/core/jni/android_database_SQLiteCommon.cpp b/core/jni/android_database_SQLiteCommon.cpp
index a94b9d2..3484467 100644
--- a/core/jni/android_database_SQLiteCommon.cpp
+++ b/core/jni/android_database_SQLiteCommon.cpp
@@ -68,50 +68,53 @@
             exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException";
             break;
         case SQLITE_CONSTRAINT:
-           exceptionClass = "android/database/sqlite/SQLiteConstraintException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteConstraintException";
+            break;
         case SQLITE_ABORT:
-           exceptionClass = "android/database/sqlite/SQLiteAbortException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteAbortException";
+            break;
         case SQLITE_DONE:
-           exceptionClass = "android/database/sqlite/SQLiteDoneException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteDoneException";
+            break;
         case SQLITE_FULL:
-           exceptionClass = "android/database/sqlite/SQLiteFullException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteFullException";
+            break;
         case SQLITE_MISUSE:
-           exceptionClass = "android/database/sqlite/SQLiteMisuseException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteMisuseException";
+            break;
         case SQLITE_PERM:
-           exceptionClass = "android/database/sqlite/SQLiteAccessPermException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteAccessPermException";
+            break;
         case SQLITE_BUSY:
-           exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException";
+            break;
         case SQLITE_LOCKED:
-           exceptionClass = "android/database/sqlite/SQLiteTableLockedException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteTableLockedException";
+            break;
         case SQLITE_READONLY:
-           exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException";
+            break;
         case SQLITE_CANTOPEN:
-           exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException";
+            break;
         case SQLITE_TOOBIG:
-           exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException";
+            break;
         case SQLITE_RANGE:
-           exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException";
+            break;
         case SQLITE_NOMEM:
-           exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException";
+            break;
         case SQLITE_MISMATCH:
-           exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
+            break;
+        case SQLITE_INTERRUPT:
+            exceptionClass = "android/content/OperationCanceledException";
+            break;
         default:
-           exceptionClass = "android/database/sqlite/SQLiteException";
-           break;
+            exceptionClass = "android/database/sqlite/SQLiteException";
+            break;
     }
 
     if (sqlite3Message != NULL && message != NULL) {
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index d0d53f6..e061ac3 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -67,8 +67,10 @@
     const String8 path;
     const String8 label;
 
+    volatile bool canceled;
+
     SQLiteConnection(sqlite3* db, int openFlags, const String8& path, const String8& label) :
-        db(db), openFlags(openFlags), path(path), label(label) { }
+        db(db), openFlags(openFlags), path(path), label(label), canceled(false) { }
 };
 
 // Called each time a statement begins execution, when tracing is enabled.
@@ -85,6 +87,12 @@
             connection->label.string(), sql, tm * 0.000001f);
 }
 
+// Called after each SQLite VM instruction when cancelation is enabled.
+static int sqliteProgressHandlerCallback(void* data) {
+    SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
+    return connection->canceled;
+}
+
 
 static jint nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
         jstring labelStr, jboolean enableTrace, jboolean enableProfile) {
@@ -871,6 +879,24 @@
     return cur;
 }
 
+static void nativeCancel(JNIEnv* env, jobject clazz, jint connectionPtr) {
+    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
+    connection->canceled = true;
+}
+
+static void nativeResetCancel(JNIEnv* env, jobject clazz, jint connectionPtr,
+        jboolean cancelable) {
+    SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
+    connection->canceled = false;
+
+    if (cancelable) {
+        sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
+                connection);
+    } else {
+        sqlite3_progress_handler(connection->db, 0, NULL, NULL);
+    }
+}
+
 
 static JNINativeMethod sMethods[] =
 {
@@ -923,6 +949,10 @@
             (void*)nativeExecuteForCursorWindow },
     { "nativeGetDbLookaside", "(I)I",
             (void*)nativeGetDbLookaside },
+    { "nativeCancel", "(I)V",
+            (void*)nativeCancel },
+    { "nativeResetCancel", "(IZ)V",
+            (void*)nativeResetCancel },
 };
 
 #define FIND_CLASS(var, className) \
diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp
new file mode 100644
index 0000000..7f40a5c
--- /dev/null
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SerialPortJNI"
+
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+
+using namespace android;
+
+static jfieldID field_context;
+
+static void
+android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescriptor, jint speed)
+{
+    switch (speed) {
+        case 50:
+            speed = B50;
+            break;
+        case 75:
+            speed = B75;
+            break;
+        case 110:
+            speed = B110;
+            break;
+        case 134:
+            speed = B134;
+            break;
+        case 150:
+            speed = B150;
+            break;
+        case 200:
+            speed = B200;
+            break;
+        case 300:
+            speed = B300;
+            break;
+        case 600:
+            speed = B600;
+            break;
+        case 1200:
+            speed = B1200;
+            break;
+        case 1800:
+            speed = B1800;
+            break;
+        case 2400:
+            speed = B2400;
+            break;
+        case 4800:
+            speed = B4800;
+            break;
+        case 9600:
+            speed = B9600;
+            break;
+        case 19200:
+            speed = B19200;
+            break;
+        case 38400:
+            speed = B38400;
+            break;
+        case 57600:
+            speed = B57600;
+            break;
+        case 115200:
+            speed = B115200;
+            break;
+        case 230400:
+            speed = B230400;
+            break;
+        case 460800:
+            speed = B460800;
+            break;
+        case 500000:
+            speed = B500000;
+            break;
+        case 576000:
+            speed = B576000;
+            break;
+        case 921600:
+            speed = B921600;
+            break;
+        case 1000000:
+            speed = B1000000;
+            break;
+        case 1152000:
+            speed = B1152000;
+            break;
+        case 1500000:
+            speed = B1500000;
+            break;
+        case 2000000:
+            speed = B2000000;
+            break;
+        case 2500000:
+            speed = B2500000;
+            break;
+        case 3000000:
+            speed = B3000000;
+            break;
+        case 3500000:
+            speed = B3500000;
+            break;
+        case 4000000:
+            speed = B4000000;
+            break;
+        default:
+            jniThrowException(env, "java/lang/IllegalArgumentException",
+                              "Unsupported serial port speed");
+            return;
+    }
+
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
+    fd = dup(fd);
+    if (fd < 0) {
+        jniThrowException(env, "java/io/IOException", "Could not open serial port");
+        return;
+    }
+    env->SetIntField(thiz, field_context, fd);
+
+    struct termios tio;
+    if (tcgetattr(fd, &tio))
+        memset(&tio, 0, sizeof(tio));
+
+    tio.c_cflag =  speed | CS8 | CLOCAL | CREAD;
+    // Disable output processing, including messing with end-of-line characters.
+    tio.c_oflag &= ~OPOST;
+    tio.c_iflag = IGNPAR;
+    tio.c_lflag = 0; /* turn of CANON, ECHO*, etc */
+    /* no timeout but request at least one character per read */
+    tio.c_cc[VTIME] = 0;
+    tio.c_cc[VMIN] = 1;
+    tcsetattr(fd, TCSANOW, &tio);
+    tcflush(fd, TCIFLUSH);
+}
+
+static void
+android_hardware_SerialPort_close(JNIEnv *env, jobject thiz)
+{
+    int fd = env->GetIntField(thiz, field_context);
+    close(fd);
+    env->SetIntField(thiz, field_context, -1);
+}
+
+static jint
+android_hardware_SerialPort_read_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
+{
+    int fd = env->GetIntField(thiz, field_context);
+    jbyte* buf = (jbyte *)malloc(length);
+    if (!buf) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        return -1;
+    }
+
+    int ret = read(fd, buf, length);
+    if (ret > 0) {
+        // copy data from native buffer to Java buffer
+        env->SetByteArrayRegion(buffer, 0, ret, buf);
+    }
+
+    free(buf);
+    if (ret < 0)
+        jniThrowException(env, "java/io/IOException", NULL);
+    return ret;
+}
+
+static jint
+android_hardware_SerialPort_read_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
+{
+    int fd = env->GetIntField(thiz, field_context);
+
+    jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
+    if (!buf) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
+        return -1;
+    }
+
+    int ret = read(fd, buf, length);
+    if (ret < 0)
+        jniThrowException(env, "java/io/IOException", NULL);
+    return ret;
+}
+
+static void
+android_hardware_SerialPort_write_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length)
+{
+    int fd = env->GetIntField(thiz, field_context);
+    jbyte* buf = (jbyte *)malloc(length);
+    if (!buf) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        return;
+    }
+    env->GetByteArrayRegion(buffer, 0, length, buf);
+
+    jint ret = write(fd, buf, length);
+    free(buf);
+    if (ret < 0)
+        jniThrowException(env, "java/io/IOException", NULL);
+}
+
+static void
+android_hardware_SerialPort_write_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length)
+{
+    int fd = env->GetIntField(thiz, field_context);
+
+    jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer);
+    if (!buf) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct");
+        return;
+    }
+    int ret = write(fd, buf, length);
+    if (ret < 0)
+        jniThrowException(env, "java/io/IOException", NULL);
+}
+
+static void
+android_hardware_SerialPort_send_break(JNIEnv *env, jobject thiz)
+{
+    int fd = env->GetIntField(thiz, field_context);
+    tcsendbreak(fd, 0);
+}
+
+static JNINativeMethod method_table[] = {
+    {"native_open",             "(Ljava/io/FileDescriptor;I)V",
+                                        (void *)android_hardware_SerialPort_open},
+    {"native_close",            "()V",  (void *)android_hardware_SerialPort_close},
+    {"native_read_array",       "([BI)I",
+                                        (void *)android_hardware_SerialPort_read_array},
+    {"native_read_direct",      "(Ljava/nio/ByteBuffer;I)I",
+                                        (void *)android_hardware_SerialPort_read_direct},
+    {"native_write_array",      "([BI)V",
+                                        (void *)android_hardware_SerialPort_write_array},
+    {"native_write_direct",     "(Ljava/nio/ByteBuffer;I)V",
+                                        (void *)android_hardware_SerialPort_write_direct},
+    {"native_send_break",       "()V",  (void *)android_hardware_SerialPort_send_break},
+};
+
+int register_android_hardware_SerialPort(JNIEnv *env)
+{
+    jclass clazz = env->FindClass("android/hardware/SerialPort");
+    if (clazz == NULL) {
+        ALOGE("Can't find android/hardware/SerialPort");
+        return -1;
+    }
+    field_context = env->GetFieldID(clazz, "mNativeContext", "I");
+    if (field_context == NULL) {
+        ALOGE("Can't find SerialPort.mNativeContext");
+        return -1;
+    }
+
+    return AndroidRuntime::registerNativeMethods(env, "android/hardware/SerialPort",
+            method_table, NELEM(method_table));
+}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 3f1af86..68a8de8 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -157,7 +157,7 @@
     int frameSize = nbChannels * bytesPerSample;
     size_t frameCount = buffSizeInBytes / frameSize;
     
-    if (source >= AUDIO_SOURCE_CNT) {
+    if (uint32_t(source) >= AUDIO_SOURCE_CNT) {
         ALOGE("Error creating AudioRecord: unknown source.");
         return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
     }
@@ -198,7 +198,7 @@
     // we use a weak reference so the AudioRecord object can be garbage collected.
     lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
     
-    lpRecorder->set(source,
+    lpRecorder->set((audio_source_t) source,
         sampleRateInHertz,
         format,        // word length, PCM
         channels,
@@ -220,7 +220,7 @@
         ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
         goto native_init_failure;
     }
-    // read the audio session ID back from AudioTrack in case a new session was created during set()
+    // read the audio session ID back from AudioRecord in case a new session was created during set()
     nSession[0] = lpRecorder->getSessionId();
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6b4c5e8..ee5eb7e 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1,4 +1,4 @@
-/* //device/libs/android_runtime/android_media_AudioSystem.cpp
+/*
 **
 ** Copyright 2006, The Android Open Source Project
 **
@@ -204,6 +204,38 @@
     return index;
 }
 
+static int
+android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
+{
+    return check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
+}
+
+static jfloat
+android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
+{
+    float value;
+    if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
+        value = -1.0;
+    }
+    return value;
+}
+
+static int
+android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
+{
+    return check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
+}
+
+static jfloat
+android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
+{
+    bool mute;
+    if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
+        mute = false;
+    }
+    return mute;
+}
+
 static jint
 android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
 {
@@ -226,6 +258,10 @@
     {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
     {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
     {"getStreamVolumeIndex","(II)I",    (void *)android_media_AudioSystem_getStreamVolumeIndex},
+    {"setMasterVolume",     "(F)I",     (void *)android_media_AudioSystem_setMasterVolume},
+    {"getMasterVolume",     "()F",      (void *)android_media_AudioSystem_getMasterVolume},
+    {"setMasterMute",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMute},
+    {"getMasterMute",       "()Z",      (void *)android_media_AudioSystem_getMasterMute},
     {"getDevicesForStream", "(I)I",     (void *)android_media_AudioSystem_getDevicesForStream},
 };
 
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 53a0501..544b4c0 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -1,4 +1,4 @@
-/* //device/libs/android_runtime/android_media_AudioSystem.cpp
+/*
  **
  ** Copyright 2008, The Android Open Source Project
  **
@@ -39,7 +39,7 @@
 static fields_t fields;
 
 static jboolean android_media_ToneGenerator_startTone(JNIEnv *env, jobject thiz, jint toneType, jint durationMs) {
-    ALOGV("android_media_ToneGenerator_startTone: %x\n", (int)thiz);
+    ALOGV("android_media_ToneGenerator_startTone: %x", (int)thiz);
 
     ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
             fields.context);
@@ -48,16 +48,16 @@
         return false;
     }
 
-    return lpToneGen->startTone(toneType, durationMs);
+    return lpToneGen->startTone((ToneGenerator::tone_type) toneType, durationMs);
 }
 
 static void android_media_ToneGenerator_stopTone(JNIEnv *env, jobject thiz) {
-    ALOGV("android_media_ToneGenerator_stopTone: %x\n", (int)thiz);
+    ALOGV("android_media_ToneGenerator_stopTone: %x", (int)thiz);
 
     ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
             fields.context);
 
-    ALOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
+    ALOGV("ToneGenerator lpToneGen: %x", (unsigned int)lpToneGen);
     if (lpToneGen == NULL) {
         jniThrowRuntimeException(env, "Method called after release()");
         return;
@@ -68,13 +68,11 @@
 static void android_media_ToneGenerator_release(JNIEnv *env, jobject thiz) {
     ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
             fields.context);
-    ALOGV("android_media_ToneGenerator_release lpToneGen: %x\n", (int)lpToneGen);
+    ALOGV("android_media_ToneGenerator_release lpToneGen: %x", (int)lpToneGen);
 
     env->SetIntField(thiz, fields.context, 0);
 
-    if (lpToneGen) {
-        delete lpToneGen;
-    }
+    delete lpToneGen;
 }
 
 static void android_media_ToneGenerator_native_setup(JNIEnv *env, jobject thiz,
@@ -83,17 +81,17 @@
 
     env->SetIntField(thiz, fields.context, 0);
 
-    ALOGV("android_media_ToneGenerator_native_setup jobject: %x\n", (int)thiz);
+    ALOGV("android_media_ToneGenerator_native_setup jobject: %x", (int)thiz);
 
     if (lpToneGen == NULL) {
-        ALOGE("ToneGenerator creation failed \n");
+        ALOGE("ToneGenerator creation failed");
         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
         return;
     }
-    ALOGV("ToneGenerator lpToneGen: %x\n", (unsigned int)lpToneGen);
+    ALOGV("ToneGenerator lpToneGen: %x", (unsigned int)lpToneGen);
 
     if (!lpToneGen->isInited()) {
-        ALOGE("ToneGenerator init failed \n");
+        ALOGE("ToneGenerator init failed");
         jniThrowRuntimeException(env, "Init failed");
         return;
     }
@@ -101,18 +99,18 @@
     // Stow our new C++ ToneGenerator in an opaque field in the Java object.
     env->SetIntField(thiz, fields.context, (int)lpToneGen);
 
-    ALOGV("ToneGenerator fields.context: %x\n", env->GetIntField(thiz, fields.context));
+    ALOGV("ToneGenerator fields.context: %x", env->GetIntField(thiz, fields.context));
 }
 
 static void android_media_ToneGenerator_native_finalize(JNIEnv *env,
         jobject thiz) {
-    ALOGV("android_media_ToneGenerator_native_finalize jobject: %x\n", (int)thiz);
+    ALOGV("android_media_ToneGenerator_native_finalize jobject: %x", (int)thiz);
 
     ToneGenerator *lpToneGen = (ToneGenerator *)env->GetIntField(thiz,
             fields.context);
 
-    if (lpToneGen) {
-        ALOGV("delete lpToneGen: %x\n", (int)lpToneGen);
+    if (lpToneGen != NULL) {
+        ALOGV("delete lpToneGen: %p", lpToneGen);
         delete lpToneGen;
     }
 }
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 2ac3ca8..c5ff16e 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -116,14 +116,9 @@
     return (jboolean)(::wifi_unload_driver() == 0);
 }
 
-static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject)
+static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject, jboolean p2pSupported)
 {
-    return (jboolean)(::wifi_start_supplicant() == 0);
-}
-
-static jboolean android_net_wifi_startP2pSupplicant(JNIEnv* env, jobject)
-{
-    return (jboolean)(::wifi_start_p2p_supplicant() == 0);
+    return (jboolean)(::wifi_start_supplicant(p2pSupported) == 0);
 }
 
 static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject)
@@ -207,8 +202,7 @@
     { "loadDriver", "()Z",  (void *)android_net_wifi_loadDriver },
     { "isDriverLoaded", "()Z",  (void *)android_net_wifi_isDriverLoaded },
     { "unloadDriver", "()Z",  (void *)android_net_wifi_unloadDriver },
-    { "startSupplicant", "()Z",  (void *)android_net_wifi_startSupplicant },
-    { "startP2pSupplicant", "()Z",  (void *)android_net_wifi_startP2pSupplicant },
+    { "startSupplicant", "(Z)Z",  (void *)android_net_wifi_startSupplicant },
     { "killSupplicant", "()Z",  (void *)android_net_wifi_killSupplicant },
     { "connectToSupplicant", "(Ljava/lang/String;)Z",
             (void *)android_net_wifi_connectToSupplicant },
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 990a617..e00970a 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -739,6 +739,11 @@
     return IPCThreadState::self()->getCallingUid();
 }
 
+static jint android_os_Binder_getOrigCallingUid(JNIEnv* env, jobject clazz)
+{
+    return IPCThreadState::self()->getOrigCallingUid();
+}
+
 static jlong android_os_Binder_clearCallingIdentity(JNIEnv* env, jobject clazz)
 {
     return IPCThreadState::self()->clearCallingIdentity();
@@ -810,6 +815,7 @@
      /* name, signature, funcPtr */
     { "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },
     { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
+    { "getOrigCallingUidNative", "()I", (void*)android_os_Binder_getOrigCallingUid },
     { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
     { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
     { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },
diff --git a/core/jni/android_view_Display.cpp b/core/jni/android_view_Display.cpp
index 366a52e..f076cc8 100644
--- a/core/jni/android_view_Display.cpp
+++ b/core/jni/android_view_Display.cpp
@@ -28,6 +28,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 #include <utils/Log.h>
+#include <cutils/properties.h>
 
 // ----------------------------------------------------------------------------
 
@@ -44,6 +45,7 @@
     jfieldID ydpi;
 };
 static offsets_t offsets;
+static bool headless = false;
 
 // ----------------------------------------------------------------------------
 
@@ -51,10 +53,19 @@
         JNIEnv* env, jobject clazz, jint dpy)
 {
     DisplayInfo info;
-    status_t err = SurfaceComposerClient::getDisplayInfo(DisplayID(dpy), &info);
-    if (err < 0) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
+    if (headless) {
+        // initialize dummy display with reasonable values
+        info.pixelFormatInfo.format = 1; // RGB_8888
+        info.fps = 60;
+        info.density = 160;
+        info.xdpi = 160;
+        info.ydpi = 160;
+    } else {
+        status_t err = SurfaceComposerClient::getDisplayInfo(DisplayID(dpy), &info);
+        if (err < 0) {
+            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+            return;
+        }
     }
     env->SetIntField(clazz, offsets.pixelFormat,info.pixelFormatInfo.format);
     env->SetFloatField(clazz, offsets.fps,      info.fps);
@@ -66,6 +77,7 @@
 static jint android_view_Display_getRawWidthNative(
         JNIEnv* env, jobject clazz)
 {
+    if (headless) return 640;
     DisplayID dpy = env->GetIntField(clazz, offsets.display);
     return SurfaceComposerClient::getDisplayWidth(dpy);
 }
@@ -73,6 +85,7 @@
 static jint android_view_Display_getRawHeightNative(
         JNIEnv* env, jobject clazz)
 {
+    if (headless) return 480;
     DisplayID dpy = env->GetIntField(clazz, offsets.display);
     return SurfaceComposerClient::getDisplayHeight(dpy);
 }
@@ -80,6 +93,7 @@
 static jint android_view_Display_getOrientation(
         JNIEnv* env, jobject clazz)
 {
+    if (headless) return 0; // Surface.ROTATION_0
     DisplayID dpy = env->GetIntField(clazz, offsets.display);
     return SurfaceComposerClient::getDisplayOrientation(dpy);
 }
@@ -87,6 +101,7 @@
 static jint android_view_Display_getDisplayCount(
         JNIEnv* env, jclass clazz)
 {
+    if (headless) return 1;
     return SurfaceComposerClient::getNumberOfDisplays();
 }
 
@@ -113,6 +128,12 @@
 
 void nativeClassInit(JNIEnv* env, jclass clazz)
 {
+    char value[PROPERTY_VALUE_MAX];
+
+    property_get("ro.config.headless", value, "0");
+    if (strcmp(value, "1") == 0)
+        headless = true;
+
     offsets.display     = env->GetFieldID(clazz, "mDisplay", "I");
     offsets.pixelFormat = env->GetFieldID(clazz, "mPixelFormat", "I");
     offsets.fps         = env->GetFieldID(clazz, "mRefreshRate", "F");
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 25397b5..8a1c4a9 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -59,21 +59,20 @@
     sp<Looper> mLooper;
     DisplayEventReceiver mReceiver;
     bool mWaitingForVsync;
-    bool mFdCallbackRegistered;
 };
 
 
 NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
         jobject receiverObj, const sp<Looper>& looper) :
         mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
-        mLooper(looper), mWaitingForVsync(false), mFdCallbackRegistered(false) {
+        mLooper(looper), mWaitingForVsync(false) {
     ALOGV("receiver %p ~ Initializing input event receiver.", this);
 }
 
 NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
     ALOGV("receiver %p ~ Disposing display event receiver.", this);
 
-    if (mFdCallbackRegistered) {
+    if (!mReceiver.initCheck()) {
         mLooper->removeFd(mReceiver.getFd());
     }
 
@@ -88,6 +87,11 @@
         return result;
     }
 
+    int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
+            handleReceiveCallback, this);
+    if (rc < 0) {
+        return UNKNOWN_ERROR;
+    }
     return OK;
 }
 
@@ -113,15 +117,6 @@
             return status;
         }
 
-        if (!mFdCallbackRegistered) {
-            int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
-                    handleReceiveCallback, this);
-            if (rc < 0) {
-                return UNKNOWN_ERROR;
-            }
-            mFdCallbackRegistered = true;
-        }
-
         mWaitingForVsync = true;
     }
     return OK;
@@ -133,7 +128,6 @@
     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
         ALOGE("Display event receiver pipe was closed or an error occurred.  "
                 "events=0x%x", events);
-        r->mFdCallbackRegistered = false;
         return 0; // remove the callback
     }
 
@@ -150,7 +144,7 @@
     DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
     ssize_t n;
     while ((n = r->mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
-        ALOGV("receiver %p ~ Read %d events.", this, int(n));
+        ALOGV("receiver %p ~ Read %d events.", data, int(n));
         while (n-- > 0) {
             if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
                 vsyncTimestamp = buf[n].header.timestamp;
@@ -161,20 +155,20 @@
     }
 
     if (vsyncTimestamp < 0) {
-        ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this);
+        ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", data);
         return 1; // keep the callback, did not obtain a vsync pulse
     }
 
     ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d",
-            this, vsyncTimestamp, vsyncCount);
+            data, vsyncTimestamp, vsyncCount);
     r->mWaitingForVsync = false;
 
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
-    ALOGV("receiver %p ~ Invoking vsync handler.", this);
+    ALOGV("receiver %p ~ Invoking vsync handler.", data);
     env->CallVoidMethod(r->mReceiverObjGlobal,
             gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
-    ALOGV("receiver %p ~ Returned from vsync handler.", this);
+    ALOGV("receiver %p ~ Returned from vsync handler.", data);
 
     if (env->ExceptionCheck()) {
         ALOGE("An exception occurred while dispatching a vsync event.");
@@ -182,13 +176,7 @@
         env->ExceptionClear();
     }
 
-    // Check whether dispatchVsync called scheduleVsync reentrantly and set mWaitingForVsync.
-    // If so, keep the callback, otherwise remove it.
-    if (r->mWaitingForVsync) {
-        return 1; // keep the callback
-    }
-    r->mFdCallbackRegistered = false;
-    return 0; // remove the callback
+    return 1; // keep the callback
 }
 
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 5811ddd..e19bb38 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -188,6 +188,14 @@
     renderer->finish();
 }
 
+static jint android_view_GLES20Canvas_getStencilSize(JNIEnv* env, jobject clazz) {
+    return OpenGLRenderer::getStencilSize();
+}
+
+// ----------------------------------------------------------------------------
+// Functor
+// ----------------------------------------------------------------------------
+
 static bool android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Functor *functor) {
     android::uirenderer::Rect dirty;
@@ -502,19 +510,11 @@
 
 static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
         jfloat x, jfloat y, int flags, SkPaint* paint) {
-    sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-    value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, flags);
+    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+            text, 0, count, count, flags);
     if (value == NULL) {
-        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                String8(text, count).string());
         return;
     }
-#else
-    value = new TextLayoutCacheValue(count);
-    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
-            text, 0, count, count, flags);
-#endif
     const jchar* glyphs = value->getGlyphs();
     size_t glyphsCount = value->getGlyphsCount();
     int bytesCount = glyphsCount * sizeof(jchar);
@@ -524,19 +524,11 @@
 static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
         jint start, jint count, jint contextCount, jfloat x, jfloat y,
         int flags, SkPaint* paint) {
-    sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-    value = TextLayoutCache::getInstance().getValue(paint, text, start, count, contextCount, flags);
+    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+            text, start, count, contextCount, flags);
     if (value == NULL) {
-        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                String8(text + start, count).string());
         return;
     }
-#else
-    value = new TextLayoutCacheValue(count);
-    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
-            text, start, count, contextCount, flags);
-#endif
     const jchar* glyphs = value->getGlyphs();
     size_t glyphsCount = value->getGlyphsCount();
     int bytesCount = glyphsCount * sizeof(jchar);
@@ -583,20 +575,11 @@
 
 static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count,
         const jfloat* positions, jint dirFlags, SkPaint* paint) {
-    sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
-    value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, dirFlags);
+    sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+            text, 0, count, count, dirFlags);
     if (value == NULL) {
-        ALOGE("Cannot get TextLayoutCache value for text = '%s'",
-                String8(text, count).string());
         return;
     }
-#else
-    value = new TextLayoutCacheValue(count);
-    TextLayoutEngine::getInstance().computeValues(value.get(), paint,
-            text, 0, count, count, dirFlags);
-#endif
-
     const jchar* glyphs = value->getGlyphs();
     size_t glyphsCount = value->getGlyphsCount();
     if (count < int(glyphsCount)) glyphsCount = count;
@@ -643,6 +626,15 @@
     return displayList->getSize();
 }
 
+static void android_view_GLES20Canvas_setDisplayListName(JNIEnv* env,
+        jobject clazz, DisplayList* displayList, jstring name) {
+    if (name != NULL) {
+        const char* textArray = env->GetStringUTFChars(name, NULL);
+        displayList->setName(textArray);
+        env->ReleaseStringUTFChars(name, textArray);
+    }
+}
+
 static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
         jobject clazz) {
     return new DisplayListRenderer;
@@ -833,6 +825,8 @@
     { "nPrepareDirty",      "(IIIIIZ)V",       (void*) android_view_GLES20Canvas_prepareDirty },
     { "nFinish",            "(I)V",            (void*) android_view_GLES20Canvas_finish },
 
+    { "nGetStencilSize",    "()I",             (void*) android_view_GLES20Canvas_getStencilSize },
+
     { "nCallDrawGLFunction", "(II)Z",
             (void*) android_view_GLES20Canvas_callDrawGLFunction },
 
@@ -905,10 +899,14 @@
     { "nGetDisplayList",         "(II)I",      (void*) android_view_GLES20Canvas_getDisplayList },
     { "nDestroyDisplayList",     "(I)V",       (void*) android_view_GLES20Canvas_destroyDisplayList },
     { "nGetDisplayListSize",     "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListSize },
-    { "nCreateDisplayListRenderer", "()I",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
-    { "nResetDisplayListRenderer", "(I)V",     (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
+    { "nSetDisplayListName",     "(ILjava/lang/String;)V",
+                                               (void*) android_view_GLES20Canvas_setDisplayListName },
     { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;)Z",
                                                (void*) android_view_GLES20Canvas_drawDisplayList },
+
+    { "nCreateDisplayListRenderer", "()I",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
+    { "nResetDisplayListRenderer",  "(I)V",    (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
+
     { "nOutputDisplayList",      "(II)V",      (void*) android_view_GLES20Canvas_outputDisplayList },
     { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_HardwareRenderer.cpp
index 09809ec..cdcde51 100644
--- a/core/jni/android_view_HardwareRenderer.cpp
+++ b/core/jni/android_view_HardwareRenderer.cpp
@@ -22,6 +22,8 @@
 
 #include <EGL/egl_cache.h>
 
+EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -36,6 +38,12 @@
     env->ReleaseStringUTFChars(diskCachePath, cacheArray);
 }
 
+static void android_view_HardwareRenderer_beginFrame(JNIEnv* env, jobject clazz) {
+    EGLDisplay dpy = eglGetCurrentDisplay();
+    EGLSurface surf = eglGetCurrentSurface(EGL_DRAW);
+    eglBeginFrame(dpy, surf);
+}
+
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -45,6 +53,8 @@
 static JNINativeMethod gMethods[] = {
     { "nSetupShadersDiskCache", "(Ljava/lang/String;)V",
             (void*) android_view_HardwareRenderer_setupShadersDiskCache },
+    { "nBeginFrame", "()V",
+            (void*) android_view_HardwareRenderer_beginFrame },
 };
 
 int register_android_view_HardwareRenderer(JNIEnv* env) {
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index fce432b..5377425 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -199,32 +199,16 @@
         bool isInitialized = parcel->readInt32();
         if (isInitialized) {
             String8 name = parcel->readString8();
-            int32_t parcelAshmemFd = parcel->readFileDescriptor();
-            int32_t ashmemFd = dup(parcelAshmemFd);
-            if (ashmemFd < 0) {
-                ALOGE("Error %d dup ashmem fd %d.", errno, parcelAshmemFd);
-            }
-            int32_t parcelReceivePipeFd = parcel->readFileDescriptor();
-            int32_t receivePipeFd = dup(parcelReceivePipeFd);
-            if (receivePipeFd < 0) {
-                ALOGE("Error %d dup receive pipe fd %d.", errno, parcelReceivePipeFd);
-            }
-            int32_t parcelSendPipeFd = parcel->readFileDescriptor();
-            int32_t sendPipeFd = dup(parcelSendPipeFd);
-            if (sendPipeFd < 0) {
-                ALOGE("Error %d dup send pipe fd %d.", errno, parcelSendPipeFd);
-            }
-            if (ashmemFd < 0 || receivePipeFd < 0 || sendPipeFd < 0) {
-                if (ashmemFd >= 0) ::close(ashmemFd);
-                if (receivePipeFd >= 0) ::close(receivePipeFd);
-                if (sendPipeFd >= 0) ::close(sendPipeFd);
+            int32_t rawFd = parcel->readFileDescriptor();
+            int32_t dupFd = dup(rawFd);
+            if (rawFd < 0) {
+                ALOGE("Error %d dup channel fd %d.", errno, rawFd);
                 jniThrowRuntimeException(env,
                         "Could not read input channel file descriptors from parcel.");
                 return;
             }
 
-            InputChannel* inputChannel = new InputChannel(name, ashmemFd,
-                    receivePipeFd, sendPipeFd);
+            InputChannel* inputChannel = new InputChannel(name, dupFd);
             NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel);
 
             android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel);
@@ -243,9 +227,7 @@
 
             parcel->writeInt32(1);
             parcel->writeString8(inputChannel->getName());
-            parcel->writeDupFileDescriptor(inputChannel->getAshmemFd());
-            parcel->writeDupFileDescriptor(inputChannel->getReceivePipeFd());
-            parcel->writeDupFileDescriptor(inputChannel->getSendPipeFd());
+            parcel->writeDupFileDescriptor(inputChannel->getFd());
         } else {
             parcel->writeInt32(0);
         }
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index ed0acce..4b737ede 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -40,6 +40,7 @@
     jclass clazz;
 
     jmethodID dispatchInputEvent;
+    jmethodID dispatchBatchedInputEventPending;
 } gInputEventReceiverClassInfo;
 
 
@@ -50,7 +51,8 @@
             const sp<Looper>& looper);
 
     status_t initialize();
-    status_t finishInputEvent(bool handled);
+    status_t finishInputEvent(uint32_t seq, bool handled);
+    status_t consumeEvents(bool consumeBatches);
     static int handleReceiveCallback(int receiveFd, int events, void* data);
 
 protected:
@@ -60,8 +62,8 @@
     jobject mReceiverObjGlobal;
     InputConsumer mInputConsumer;
     sp<Looper> mLooper;
-    bool mEventInProgress;
     PreallocatedInputEventFactory mInputEventFactory;
+    bool mBatchedInputEventPending;
 
     const char* getInputChannelName() {
         return mInputConsumer.getChannel()->getName().string();
@@ -72,7 +74,8 @@
 NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
         jobject receiverObj, const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
         mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
-        mInputConsumer(inputChannel), mLooper(looper), mEventInProgress(false) {
+        mInputConsumer(inputChannel), mLooper(looper),
+        mBatchedInputEventPending(false) {
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName());
 #endif
@@ -83,45 +86,29 @@
     ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
 #endif
 
-    mLooper->removeFd(mInputConsumer.getChannel()->getReceivePipeFd());
-    if (mEventInProgress) {
-        mInputConsumer.sendFinishedSignal(false); // ignoring result
-    }
+    mLooper->removeFd(mInputConsumer.getChannel()->getFd());
 
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->DeleteGlobalRef(mReceiverObjGlobal);
 }
 
 status_t NativeInputEventReceiver::initialize() {
-    status_t result = mInputConsumer.initialize();
-    if (result) {
-        ALOGW("Failed to initialize input consumer for input channel '%s', status=%d",
-                getInputChannelName(), result);
-        return result;
-    }
-
-    int32_t receiveFd = mInputConsumer.getChannel()->getReceivePipeFd();
+    int32_t receiveFd = mInputConsumer.getChannel()->getFd();
     mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
     return OK;
 }
 
-status_t NativeInputEventReceiver::finishInputEvent(bool handled) {
-    if (mEventInProgress) {
+status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
 #if DEBUG_DISPATCH_CYCLE
-        ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
+    ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
 #endif
-        mEventInProgress = false;
 
-        status_t status = mInputConsumer.sendFinishedSignal(handled);
-        if (status) {
-            ALOGW("Failed to send finished signal on channel '%s'.  status=%d",
-                    getInputChannelName(), status);
-        }
-        return status;
-    } else {
-        ALOGW("Ignoring attempt to finish input event while no event is in progress.");
-        return OK;
+    status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
+    if (status) {
+        ALOGW("Failed to send finished signal on channel '%s'.  status=%d",
+                getInputChannelName(), status);
     }
+    return status;
 }
 
 int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, void* data) {
@@ -139,86 +126,101 @@
         return 1;
     }
 
-    status_t status = r->mInputConsumer.receiveDispatchSignal();
-    if (status) {
-        ALOGE("channel '%s' ~ Failed to receive dispatch signal.  status=%d",
-                r->getInputChannelName(), status);
-        return 0; // remove the callback
-    }
+    status_t status = r->consumeEvents(false /*consumeBatches*/);
+    return status == OK || status == NO_MEMORY ? 1 : 0;
+}
 
-    if (r->mEventInProgress) {
-        ALOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
-                r->getInputChannelName());
-        return 1;
-    }
+status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) {
+#if DEBUG_DISPATCH_CYCLE
+    ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s.", getInputChannelName(),
+            consumeBatches ? "true" : "false");
+#endif
 
-    InputEvent* inputEvent;
-    status = r->mInputConsumer.consume(&r->mInputEventFactory, &inputEvent);
-    if (status) {
-        ALOGW("channel '%s' ~ Failed to consume input event.  status=%d",
-                r->getInputChannelName(), status);
-        r->mInputConsumer.sendFinishedSignal(false);
-        return 1;
+    if (consumeBatches) {
+        mBatchedInputEventPending = false;
     }
 
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject inputEventObj;
-    switch (inputEvent->getType()) {
-    case AINPUT_EVENT_TYPE_KEY:
+    for (;;) {
+        uint32_t seq;
+        InputEvent* inputEvent;
+        status_t status = mInputConsumer.consume(&mInputEventFactory,
+                consumeBatches, &seq, &inputEvent);
+        if (status) {
+            if (status == WOULD_BLOCK) {
+                if (mInputConsumer.hasPendingBatch() && !mBatchedInputEventPending) {
+                    // There is a pending batch.  Come back later.
+                    mBatchedInputEventPending = true;
 #if DEBUG_DISPATCH_CYCLE
-        ALOGD("channel '%s' ~ Received key event.",
-                r->getInputChannelName());
+                    ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
+                            getInputChannelName());
 #endif
-        inputEventObj = android_view_KeyEvent_fromNative(env,
-                static_cast<KeyEvent*>(inputEvent));
-        break;
+                    env->CallVoidMethod(mReceiverObjGlobal,
+                            gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
 
-    case AINPUT_EVENT_TYPE_MOTION:
+                    if (env->ExceptionCheck()) {
+                        ALOGE("channel '%s' ~ An exception occurred while dispatching that "
+                                "batched input events are pending.", getInputChannelName());
+                        LOGE_EX(env);
+                        env->ExceptionClear();
+                        mBatchedInputEventPending = false; // try again later
+                    }
+                }
+                return OK;
+            }
+            ALOGE("channel '%s' ~ Failed to consume input event.  status=%d",
+                    getInputChannelName(), status);
+            return status;
+        }
+        assert(inputEvent);
+
+        jobject inputEventObj;
+        switch (inputEvent->getType()) {
+        case AINPUT_EVENT_TYPE_KEY:
 #if DEBUG_DISPATCH_CYCLE
-        ALOGD("channel '%s' ~ Received motion event.",
-                r->getInputChannelName());
+            ALOGD("channel '%s' ~ Received key event.", getInputChannelName());
 #endif
-        inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
-                static_cast<MotionEvent*>(inputEvent));
-        break;
+            inputEventObj = android_view_KeyEvent_fromNative(env,
+                    static_cast<KeyEvent*>(inputEvent));
+            break;
 
-    default:
-        assert(false); // InputConsumer should prevent this from ever happening
-        inputEventObj = NULL;
-    }
+        case AINPUT_EVENT_TYPE_MOTION:
+#if DEBUG_DISPATCH_CYCLE
+            ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
+#endif
+            inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
+                    static_cast<MotionEvent*>(inputEvent));
+            break;
 
-    if (!inputEventObj) {
-        ALOGW("channel '%s' ~ Failed to obtain event object.",
-                r->getInputChannelName());
-        r->mInputConsumer.sendFinishedSignal(false);
-        return 1;
-    }
+        default:
+            assert(false); // InputConsumer should prevent this from ever happening
+            inputEventObj = NULL;
+        }
 
-    r->mEventInProgress = true;
+        if (!inputEventObj) {
+            ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
+            mInputConsumer.sendFinishedSignal(seq, false);
+            return NO_MEMORY;
+        }
 
 #if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Invoking input handler.", r->getInputChannelName());
+        ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
 #endif
-    env->CallVoidMethod(r->mReceiverObjGlobal,
-            gInputEventReceiverClassInfo.dispatchInputEvent, inputEventObj);
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Returned from input handler.", r->getInputChannelName());
-#endif
+        env->CallVoidMethod(mReceiverObjGlobal,
+                gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
 
-    if (env->ExceptionCheck()) {
-        ALOGE("channel '%s' ~ An exception occurred while dispatching an event.",
-                r->getInputChannelName());
-        LOGE_EX(env);
-        env->ExceptionClear();
+        env->DeleteLocalRef(inputEventObj);
 
-        if (r->mEventInProgress) {
-            r->mInputConsumer.sendFinishedSignal(false);
-            r->mEventInProgress = false;
+        if (env->ExceptionCheck()) {
+            ALOGE("channel '%s' ~ An exception occurred while dispatching an event.",
+                    getInputChannelName());
+            LOGE_EX(env);
+            env->ExceptionClear();
+
+            mInputConsumer.sendFinishedSignal(seq, false);
+            return OK;
         }
     }
-
-    env->DeleteLocalRef(inputEventObj);
-    return 1;
 }
 
 
@@ -257,10 +259,11 @@
     receiver->decStrong(gInputEventReceiverClassInfo.clazz); // drop reference held by the object
 }
 
-static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr, jboolean handled) {
+static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,
+        jint seq, jboolean handled) {
     sp<NativeInputEventReceiver> receiver =
             reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
-    status_t status = receiver->finishInputEvent(handled);
+    status_t status = receiver->finishInputEvent(seq, handled);
     if (status) {
         String8 message;
         message.appendFormat("Failed to finish input event.  status=%d", status);
@@ -268,17 +271,29 @@
     }
 }
 
+static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr) {
+    sp<NativeInputEventReceiver> receiver =
+            reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+    status_t status = receiver->consumeEvents(true /*consumeBatches*/);
+    if (status) {
+        String8 message;
+        message.appendFormat("Failed to consume batched input event.  status=%d", status);
+        jniThrowRuntimeException(env, message.string());
+    }
+}
+
 
 static JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
             "(Landroid/view/InputEventReceiver;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I",
             (void*)nativeInit },
-    { "nativeDispose",
-            "(I)V",
+    { "nativeDispose", "(I)V",
             (void*)nativeDispose },
-    { "nativeFinishInputEvent", "(IZ)V",
-            (void*)nativeFinishInputEvent }
+    { "nativeFinishInputEvent", "(IIZ)V",
+            (void*)nativeFinishInputEvent },
+    { "nativeConsumeBatchedInputEvents", "(I)V",
+            (void*)nativeConsumeBatchedInputEvents },
 };
 
 #define FIND_CLASS(var, className) \
@@ -299,7 +314,10 @@
 
     GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchInputEvent,
             gInputEventReceiverClassInfo.clazz,
-            "dispatchInputEvent", "(Landroid/view/InputEvent;)V");
+            "dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
+    GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchBatchedInputEventPending,
+            gInputEventReceiverClassInfo.clazz,
+            "dispatchBatchedInputEventPending", "()V");
     return 0;
 }
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index bba4b47..18bcea1 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -572,7 +572,7 @@
 }
 
 static jobject Surface_screenshot(JNIEnv* env, jobject clazz, jint width, jint height,
-        jint minLayer, jint maxLayer, bool allLayers)
+        jint minLayer, jint maxLayer)
 {
     return doScreenshot(env, clazz, width, height, minLayer, maxLayer, false);
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 97658a1..68c919e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -717,6 +717,13 @@
         android:label="@string/permlab_removeTasks"
         android:description="@string/permdesc_removeTasks" />
 
+    <!-- @hide Change the screen compatibility mode of applications -->
+    <permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature"
+        android:label="@string/permlab_setScreenCompatibility"
+        android:description="@string/permdesc_setScreenCompatibility" />
+
     <!-- Allows an application to modify the current configuration, such
          as locale. -->
     <permission android:name="android.permission.CHANGE_CONFIGURATION"
@@ -1507,6 +1514,13 @@
         android:description="@string/permdesc_bindPackageVerifier"
         android:protectionLevel="signature" />
 
+    <!-- Allows applications to access serial ports via the SerialManager.
+         @hide -->
+    <permission android:name="android.permission.SERIAL_PORT"
+        android:label="@string/permlab_serialPort"
+        android:description="@string/permdesc_serialPort"
+        android:protectionLevel="normal" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/MakeJavaSymbols.sed b/core/res/MakeJavaSymbols.sed
new file mode 100644
index 0000000..d02fffa
--- /dev/null
+++ b/core/res/MakeJavaSymbols.sed
@@ -0,0 +1,25 @@
+# Run this on the errors output by javac of missing resource symbols,
+# to generate the set of <java-symbol> commands to have aapt generate
+# the symbol for them.
+#
+# For example: make framework 2>&1 | sed -n -f MakeJavaSymbols.sed | sort -u
+
+s|.*R.id.\([a-zA-Z0-9_]*\).*|  <java-symbol type="id" name="\1" />|gp
+s|.*R.attr.\([a-zA-Z0-9_]*\).*|  <java-symbol type="attr" name="\1" />|gp
+s|.*R.bool.\([a-zA-Z0-9_]*\).*|  <java-symbol type="bool" name="\1" />|gp
+s|.*R.integer.\([a-zA-Z0-9_]*\).*|  <java-symbol type="integer" name="\1" />|gp
+s|.*R.color.\([a-zA-Z0-9_]*\).*|  <java-symbol type="color" name="\1" />|gp
+s|.*R.dimen.\([a-zA-Z0-9_]*\).*|  <java-symbol type="dimen" name="\1" />|gp
+s|.*R.fraction.\([a-zA-Z0-9_]*\).*|  <java-symbol type="fraction" name="\1" />|gp
+s|.*R.string.\([a-zA-Z0-9_]*\).*|  <java-symbol type="string" name="\1" />|gp
+s|.*R.plurals.\([a-zA-Z0-9_]*\).*|  <java-symbol type="plurals" name="\1" />|gp
+s|.*R.array.\([a-zA-Z0-9_]*\).*|  <java-symbol type="array" name="\1" />|gp
+s|.*R.drawable.\([a-zA-Z0-9_]*\).*|  <java-symbol type="drawable" name="\1" />|gp
+s|.*R.layout.\([a-zA-Z0-9_]*\).*|  <java-symbol type="layout" name="\1" />|gp
+s|.*R.anim.\([a-zA-Z0-9_]*\).*|  <java-symbol type="anim" name="\1" />|gp
+s|.*R.animator.\([a-zA-Z0-9_]*\).*|  <java-symbol type="animator" name="\1" />|gp
+s|.*R.interpolator.\([a-zA-Z0-9_]*\).*|  <java-symbol type="interpolator" name="\1" />|gp
+s|.*R.menu.\([a-zA-Z0-9_]*\).*|  <java-symbol type="menu" name="\1" />|gp
+s|.*R.xml.\([a-zA-Z0-9_]*\).*|  <java-symbol type="xml" name="\1" />|gp
+s|.*R.raw.\([a-zA-Z0-9_]*\).*|  <java-symbol type="raw" name="\1" />|gp
+s|.*R.style.\([a-zA-Z0-9_]*\).*|  <java-symbol type="style" name="\1" />|gp
diff --git a/core/res/lint.xml b/core/res/lint.xml
new file mode 100644
index 0000000..822cdd7
--- /dev/null
+++ b/core/res/lint.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<lint>
+    <!-- temporary until we add frameworks support -->
+    <issue id="UnusedResources" severity="ignore" />
+
+    <issue id="PrivateResource" severity="ignore" />
+</lint>
\ No newline at end of file
diff --git a/core/res/res/anim/recents_fade_in.xml b/core/res/res/anim/recents_fade_in.xml
new file mode 100644
index 0000000..c516fadb
--- /dev/null
+++ b/core/res/res/anim/recents_fade_in.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/recents_fade_in.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@interpolator/decelerate_quad"
+        android:fromAlpha="0.0" android:toAlpha="1.0"
+        android:duration="150" />
diff --git a/core/res/res/anim/recents_fade_out.xml b/core/res/res/anim/recents_fade_out.xml
new file mode 100644
index 0000000..7468cc19
--- /dev/null
+++ b/core/res/res/anim/recents_fade_out.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/recents_fade_out.xml
+**
+** Copyright 2012, 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.
+*/
+-->
+
+<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/accelerate_quad"
+    android:fromAlpha="1.0"
+    android:toAlpha="0.0"
+    android:duration="150" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 6ffda04..19398cf 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Laat die program toe om take na die voorgrond en agtergrond te skuif. Kwaadwillige programme kan hulself sonder jou beheer na vore dwing."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"stop lopende programme"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Laat die program toe om take te verwyder en hul programme te dood. Kwaadwillige programme kan die gedrag van ander programme ontwrig."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"aktiveer programontfouting"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Laat die program toe om ontfouting vir \'n ander program af te skakel. Kwaadwillige programme kan dit dalk gebruik om ander programme te dood."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"Verander jou UI-instellings"</string>
@@ -539,30 +543,30 @@
     <item msgid="1735177144948329370">"Tuisfaks"</item>
     <item msgid="603878674477207394">"Roeper"</item>
     <item msgid="1650824275177931637">"Ander"</item>
-    <item msgid="9192514806975898961">"Gepasmaakte"</item>
+    <item msgid="9192514806975898961">"Gepasmaak"</item>
   </string-array>
   <string-array name="emailAddressTypes">
     <item msgid="8073994352956129127">"Tuis"</item>
     <item msgid="7084237356602625604">"Werk"</item>
     <item msgid="1112044410659011023">"Ander"</item>
-    <item msgid="2374913952870110618">"Gepasmaakte"</item>
+    <item msgid="2374913952870110618">"Gepasmaak"</item>
   </string-array>
   <string-array name="postalAddressTypes">
     <item msgid="6880257626740047286">"Tuis"</item>
     <item msgid="5629153956045109251">"Werk"</item>
     <item msgid="4966604264500343469">"Ander"</item>
-    <item msgid="4932682847595299369">"Gepasmaakte"</item>
+    <item msgid="4932682847595299369">"Gepasmaak"</item>
   </string-array>
   <string-array name="imAddressTypes">
     <item msgid="1738585194601476694">"Tuis"</item>
     <item msgid="1359644565647383708">"Werk"</item>
     <item msgid="7868549401053615677">"Ander"</item>
-    <item msgid="3145118944639869809">"Gepasmaakte"</item>
+    <item msgid="3145118944639869809">"Gepasmaak"</item>
   </string-array>
   <string-array name="organizationTypes">
     <item msgid="7546335612189115615">"Werk"</item>
     <item msgid="4378074129049520373">"Ander"</item>
-    <item msgid="3455047468583965104">"Gepasmaakte"</item>
+    <item msgid="3455047468583965104">"Gepasmaak"</item>
   </string-array>
   <string-array name="imProtocols">
     <item msgid="8595261363518459565">"AIM"</item>
@@ -574,7 +578,7 @@
     <item msgid="2506857312718630823">"ICQ"</item>
     <item msgid="1648797903785279353">"Jabber"</item>
   </string-array>
-    <string name="phoneTypeCustom" msgid="1644738059053355820">"Gepasmaakte"</string>
+    <string name="phoneTypeCustom" msgid="1644738059053355820">"Gepasmaak"</string>
     <string name="phoneTypeHome" msgid="2570923463033985887">"Tuis"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"Mobiel"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"Werk"</string>
@@ -595,24 +599,24 @@
     <string name="phoneTypeWorkPager" msgid="649938731231157056">"Werkroeper"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"Assistent"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
-    <string name="eventTypeCustom" msgid="7837586198458073404">"Gepasmaakte"</string>
+    <string name="eventTypeCustom" msgid="7837586198458073404">"Gepasmaak"</string>
     <string name="eventTypeBirthday" msgid="2813379844211390740">"Verjaardag"</string>
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"Herdenking"</string>
     <string name="eventTypeOther" msgid="7388178939010143077">"Ander"</string>
-    <string name="emailTypeCustom" msgid="8525960257804213846">"Gepasmaakte"</string>
+    <string name="emailTypeCustom" msgid="8525960257804213846">"Gepasmaak"</string>
     <string name="emailTypeHome" msgid="449227236140433919">"Tuis"</string>
     <string name="emailTypeWork" msgid="3548058059601149973">"Werk"</string>
     <string name="emailTypeOther" msgid="2923008695272639549">"Ander"</string>
     <string name="emailTypeMobile" msgid="119919005321166205">"Mobiel"</string>
-    <string name="postalTypeCustom" msgid="8903206903060479902">"Gepasmaakte"</string>
+    <string name="postalTypeCustom" msgid="8903206903060479902">"Gepasmaak"</string>
     <string name="postalTypeHome" msgid="8165756977184483097">"Tuis"</string>
     <string name="postalTypeWork" msgid="5268172772387694495">"Werk"</string>
     <string name="postalTypeOther" msgid="2726111966623584341">"Ander"</string>
-    <string name="imTypeCustom" msgid="2074028755527826046">"Gepasmaakte"</string>
+    <string name="imTypeCustom" msgid="2074028755527826046">"Gepasmaak"</string>
     <string name="imTypeHome" msgid="6241181032954263892">"Tuis"</string>
     <string name="imTypeWork" msgid="1371489290242433090">"Werk"</string>
     <string name="imTypeOther" msgid="5377007495735915478">"Ander"</string>
-    <string name="imProtocolCustom" msgid="6919453836618749992">"Gepasmaakte"</string>
+    <string name="imProtocolCustom" msgid="6919453836618749992">"Gepasmaak"</string>
     <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
     <string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
@@ -624,8 +628,8 @@
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
     <string name="orgTypeWork" msgid="29268870505363872">"Werk"</string>
     <string name="orgTypeOther" msgid="3951781131570124082">"Ander"</string>
-    <string name="orgTypeCustom" msgid="225523415372088322">"Gepasmaakte"</string>
-    <string name="relationTypeCustom" msgid="3542403679827297300">"Gepasmaakte"</string>
+    <string name="orgTypeCustom" msgid="225523415372088322">"Gepasmaak"</string>
+    <string name="relationTypeCustom" msgid="3542403679827297300">"Gepasmaak"</string>
     <string name="relationTypeAssistant" msgid="6274334825195379076">"Assistent"</string>
     <string name="relationTypeBrother" msgid="8757913506784067713">"Broer"</string>
     <string name="relationTypeChild" msgid="1890746277276881626">"Kind"</string>
@@ -640,7 +644,7 @@
     <string name="relationTypeRelative" msgid="1799819930085610271">"Familielid"</string>
     <string name="relationTypeSister" msgid="1735983554479076481">"Suster"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"Eggenoot"</string>
-    <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Gepasmaakte"</string>
+    <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Gepasmaak"</string>
     <string name="sipAddressTypeHome" msgid="6093598181069359295">"Tuis"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"Werk"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"Ander"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Laat die program toe om te verifieer dat \'n pakket installeerbaar is."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind aan \'n pakkieverifieerder"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Laat die houer toe om versoeke aan pakketverifieerders te rig. Dit moet nooit vir normale programme nodig wees nie."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"kry toegang tot reekspoorte"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Laat die houer toe om toegang te verkry tot reekspoorte wat die SerialManager API gebruik."</string>
     <string name="save_password_message" msgid="767344687139195790">"Wil jy hê die blaaier moet hierdie wagwoord onthou?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nie nou nie"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Onthou"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Verslag"</string>
     <string name="wait" msgid="7147118217226317732">"Wag"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Die bladsy reageer nie meer nie."\n\n"Wil jy dit toemaak?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Program herlei"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> loop nou."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> is oorspronklik laat loop."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2452a4a..8f7b70f 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"ወደ ግንባር ዎይ እና ዳራ ስራዎችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡ ያለአንተ ቁጥጥር  ተንኮል አዘል መተግበሪያዎች ራሳቸውን ወደፊት መምጣት ሊያስገድዱ ይችላሉ፡፡"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"የአሂድ ትግበራዎች አቁም"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"ተግባሮችን ለማስወገድ እና መተግበሪያዎቻቸውን ለመግደል ለመተግበሪያ ይፈቅዳል። ጎጂ የሆኑ መተግበሪያዎች የሌሎችን መተግበሪያዎችን ባህሪ ሊያውኩ ይችላሉ።"</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"የማያ ገጽ ተኳኋኝነት መድብ"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"መተግበሪያው የሌሎች መተግበሪያዎች የማያ ገጽ ተኳኋኝነት ሁናቴ እንዲቆጣጠር ይፈቅዳል። ተንኮለኛ መተግበሪያዎች የሌሎች መተግበሪያዎች ባህሪ ሊሰብሩ ይችላሉ።"</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"የትግበራ ማረሚያ አንቃ"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"ለሌላ መተግበሪያ አርምን አብራ ለመተግበሪያው ይፈቅዳሉ። ሌሎች መተግበሪያዎች ለመግደል ተንኮል አዘል መተግበሪያዎች ይሄንን ሊጠቀሙት ይችላሉ።"</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"የUI ቅንብሮችን ለውጥ"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ፓኬጅ መጫን የሚችል መሆኑን ለማረጋገጥ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"በፓኬጅ አረጋጋጭ የተወሰነ"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"የፓኬጅ አረጋጋጮችን ጥየቃ ለማድረግ ያዡ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"ተከታታይ ወደቦችን ድረስ"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API. የተከታታይ አደራጅ APIን በመጠቀም ያዡ የተከታታይ ወደቦችን እንዲደርስ ይፈቅዳል።"</string>
     <string name="save_password_message" msgid="767344687139195790">"አሳሹ ይህን ይለፍ ቃል እንዲያስታወስ ይፈልጋሉ?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"አሁን አይደለም"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"አስታውስ"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"ይሁን"</string>
     <string name="report" msgid="4060218260984795706">"ሪፖርት"</string>
     <string name="wait" msgid="7147118217226317732">"ቆይ"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"ገጹ ምላሽ የማይሰጥ ሆኗል።"\n\n"ልትዘጋው ትፈልጋለህ?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"መተግበሪያ አቅጣጫው ተቀይሯል"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> እየሄደ ነው።"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> በዋናነት የተነሳው።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 4c7a316..c9de7de 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"للسماح لتطبيق ما بنقل المهام إلى المقدمة والخلفية. قد تفرض التطبيقات الضارة نفسها إلى المقدمة بدون تحكم منك."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"إيقاف التطبيقات التي قيد التشغيل"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"للسماح للتطبيق بإزالة المهام وإنهاء تطبيقاتها. قد تعطل التطبيقات الضارة عمل التطبيقات الأخرى."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تعيين توافق الشاشة"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"السماح للتطبيق بالتحكم في وضع التوافق مع شاشة التطبيقات الأخرى. قد تتسبب التطبيقات الضارة في تعطيل سلوك التطبيقات الأخرى."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"تمكين تصحيح أخطاء التطبيق"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"للسماح للتطبيق بتشغيل تصحيح الأخطاء لتطبيق آخر. قد تستخدم التطبيقات الضارة هذا لإنهاء التطبيقات الأخرى."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغيير إعدادات واجهة المستخدم"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"السماح للتطبيق بالتحقق من إمكانية تثبيت حزمة."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"الالتزام بمحقق حزمة"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"السماح للمالك بإجراء طلبات محققي الحزمة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"الدخول إلى المنافذ التسلسلية"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"يسمح لحامله بالدخول إلى المنافذ التسلسلية باستخدام واجهة برمجة التطبيقات."</string>
     <string name="save_password_message" msgid="767344687139195790">"هل تريد من المتصفح تذكر كلمة المرور هذه؟"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"ليس الآن"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"تذكّر"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"موافق"</string>
     <string name="report" msgid="4060218260984795706">"إرسال تقرير"</string>
     <string name="wait" msgid="7147118217226317732">"انتظار"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"أصبحت الصفحة لا تستجيب."\n\n"هل تريد إغلاقها؟"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"تمت إعادة توجيه التطبيق"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل الآن."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"تم تشغيل <xliff:g id="APP_NAME">%1$s</xliff:g> من الأصل."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 0b40992..adb1338 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -27,7 +27,7 @@
     <string name="terabyteShort" msgid="231613018159186962">"Тб"</string>
     <string name="petabyteShort" msgid="5637816680144990219">"Пб"</string>
     <string name="fileSizeSuffix" msgid="7670819340156489359">"запаўняльнік<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
-    <!-- outdated translation 6071602020171759109 -->     <string name="untitled" msgid="4638956954852782576">"Безназоўны"</string>
+    <string name="untitled" msgid="4638956954852782576">"&lt;Без назвы&gt;"</string>
     <string name="ellipsis" msgid="7899829516048813237">"..."</string>
     <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Няма нумара тэлефона)"</string>
@@ -43,9 +43,9 @@
     <string name="serviceErased" msgid="1288584695297200972">"Паспяхова выдалена."</string>
     <string name="passwordIncorrect" msgid="7612208839450128715">"Няправільны пароль."</string>
     <string name="mmiComplete" msgid="8232527495411698359">"MMI завершаны."</string>
-    <!-- outdated translation 5085454289896032547 -->     <string name="badPin" msgid="9015277645546710014">"Стары PIN-код уведзены няправільна."</string>
-    <!-- outdated translation 5702522162746042460 -->     <string name="badPuk" msgid="5487257647081132201">"Няправiльны PUK-код."</string>
-    <!-- outdated translation 3695902225843339274 -->     <string name="mismatchPin" msgid="609379054496863419">"Уведзеныя PIN-коды не супадаюць."</string>
+    <string name="badPin" msgid="9015277645546710014">"Стары PIN-код уведзены няправільна."</string>
+    <string name="badPuk" msgid="5487257647081132201">"Няправільны PUK-код."</string>
+    <string name="mismatchPin" msgid="609379054496863419">"Уведзеныя PIN-коды не супадаюць."</string>
     <string name="invalidPin" msgid="3850018445187475377">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"Увядзіце PUK з 8 лічбаў ці больш."</string>
     <string name="needPuk" msgid="919668385956251611">"Ваша SIM-карта заблакавана PUK-кодам. Увядзіце PUK, каб разблакаваць карту."</string>
@@ -68,16 +68,16 @@
     <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Па змаўчанні ідэнтыфікатар АВН не абмежаваны. Наступны выклік: абмежаваны"</string>
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Налады ідэнтыфікатару АВН па змаўчанні: не абмяжавана. Наступны выклік: не абмежавана"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Служба не прадастаўляецца."</string>
-    <!-- outdated translation 5460892159398802465 -->     <string name="CLIRPermanent" msgid="3377371145926835671">"Налада ідэнтыфікатару АВН не можа быць зменена."</string>
+    <string name="CLIRPermanent" msgid="3377371145926835671">"Вы не можаце змяніць налады ідэнтыфікатара абанента, якi тэлефануе."</string>
     <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Абмежаваны доступ змяніўся"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Служба дадзеных блакуецца."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Аварыйная служба блакуецца."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Галасавая служба заблакаваная."</string>
-    <string name="RestrictedOnAllVoice" msgid="1459318899842232234">"Усе галасавыя службы заблакаваныя."</string>
+    <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"Усе галасавыя службы заблакаваны."</string>
     <string name="RestrictedOnSms" msgid="8314352327461638897">"Служба SMS заблакаваная."</string>
-    <string name="RestrictedOnVoiceData" msgid="8244438624660371717">"Службы перадачы голаса і дадзеных заблакаваныя."</string>
+    <string name="RestrictedOnVoiceData" msgid="996636487106171320">"Службы перадачы голаса/дадзеных заблакаваны."</string>
     <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Службы перадачы голаса і SMS заблакаваныя."</string>
-    <string name="RestrictedOnAll" msgid="2714924667937117304">"Усе службы дадзеных, галасавыя і SMS-службы заблакаваныя."</string>
+    <string name="RestrictedOnAll" msgid="5643028264466092821">"Усе службы перадачы дадзеных, галасавыя і SMS-службы заблакаваны."</string>
     <string name="serviceClassVoice" msgid="1258393812335258019">"Голас"</string>
     <string name="serviceClassData" msgid="872456782077937893">"Дадзеныя"</string>
     <string name="serviceClassFAX" msgid="5566624998840486475">"Факс"</string>
@@ -108,27 +108,27 @@
     <string name="fcComplete" msgid="3118848230966886575">"Код аб\'екта завершаны."</string>
     <string name="fcError" msgid="3327560126588500777">"Праблема падлучэння ці няправільны код функцыі."</string>
     <string name="httpErrorOk" msgid="1191919378083472204">"ОК"</string>
-    <string name="httpError" msgid="6603022914760066338">"Памылка сеткі."</string>
-    <string name="httpErrorLookup" msgid="4517085806977851374">"URL не знойдзены."</string>
-    <!-- outdated translation 2781440683514730227 -->     <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Схема аўтэнтыфікацыі сайта не падтрымліваецца."</string>
-    <string name="httpErrorAuth" msgid="7293960746955020542">"Няўдалая праверка на сапраўднасць."</string>
+    <string name="httpError" msgid="7956392511146698522">"Адбылася памылка сеткі."</string>
+    <string name="httpErrorLookup" msgid="4711687456111963163">"Не атрымалася знайсці URL."</string>
+    <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Схема аўтэнтыфікацыі сайта не падтрымліваецца."</string>
+    <string name="httpErrorAuth" msgid="1435065629438044534">"Памылка аўтэнтыфікацыі."</string>
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Праверка сапраўднасці праз проксі-сервер скончылася няўдала."</string>
-    <string name="httpErrorConnect" msgid="7623096283505770433">"Падключэнне да сервера не ўдалося."</string>
-    <string name="httpErrorIO" msgid="4270874999047767599">"Сервер не можа ўсталяваць сувязь. Паспрабуйце пазней."</string>
+    <string name="httpErrorConnect" msgid="8714273236364640549">"Немагчыма падлучыцца да сервера."</string>
+    <string name="httpErrorIO" msgid="2340558197489302188">"Немагчыма звязацца з серверам. Паўтарыце спробу пазней."</string>
     <string name="httpErrorTimeout" msgid="4743403703762883954">"Час чакання злучэння з серверам скончыўся."</string>
     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Старонка змяшчае зашмат перанакіраванняў сервера."</string>
-    <!-- outdated translation 5257172771607996054 -->     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Пратакол не падтрымліваецца."</string>
-    <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Бяспечнае злучэнне ўсталяваць не ўдалося."</string>
-    <string name="httpErrorBadUrl" msgid="6088183159988619736">"Старонка не можа быць адкрыта: несапраўдны URL."</string>
-    <string name="httpErrorFile" msgid="8250549644091165175">"Немагчыма атрымаць доступ да файла."</string>
-    <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Запатрабаваны файл не знойдзены."</string>
+    <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Пратакол не падтрымліваецца."</string>
+    <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Немагчыма ўсталяваць бяспечнае злучэнне."</string>
+    <string name="httpErrorBadUrl" msgid="3636929722728881972">"Немагчыма адкрыць старонку, таму што URL несапраўдны."</string>
+    <string name="httpErrorFile" msgid="2170788515052558676">"Немагчыма атрымаць доступ да файла."</string>
+    <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Немагчыма знайсці патрабаваны файл."</string>
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Апрацоўваецца занадта шмат запытаў. Паспрабуйце яшчэ раз пазней."</string>
-    <string name="notification_title" msgid="1259940370369187045">"Памылка ўваходу ў сістэму для ўліковага запісу <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+    <string name="notification_title" msgid="8967710025036163822">"Памылка ўваходу ва ўлiковы запiс <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"Сінхранізацыя"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Сінхранізацыя"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Занадта шмат выдаленняў <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
-    <string name="low_memory" product="tablet" msgid="2292820184396262278">"Памяць планшэта поўная! Выдаліце ​​некаторыя файлы, каб вызваліць месца."</string>
-    <string name="low_memory" product="default" msgid="6632412458436461203">"Памяць тэлефона поўная! Выдаліце ​​некаторыя файлы, каб вызваліць прастору."</string>
+    <string name="low_memory" product="tablet" msgid="6494019234102154896">"Памяць планшэта поўная. Выдаліце некаторыя файлы, каб вызваліць месца."</string>
+    <string name="low_memory" product="default" msgid="3475999286680000541">"Памяць тэлефона поўная. Выдаліце ​​некаторыя файлы, каб вызваліць месца."</string>
     <string name="me" msgid="6545696007631404292">"Я"</string>
     <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Параметры планшэта"</string>
     <string name="power_dialog" product="default" msgid="1319919075463988638">"Параметры тэлефона"</string>
@@ -137,12 +137,15 @@
     <string name="turn_off_radio" msgid="8198784949987062346">"Адключыць бесправадную сетку"</string>
     <string name="screen_lock" msgid="799094655496098153">"Блакіроўка экрана"</string>
     <string name="power_off" msgid="4266614107412865048">"Выключыць"</string>
+    <string name="silent_mode_silent" msgid="319298163018473078">"Званок выкл."</string>
+    <string name="silent_mode_vibrate" msgid="7072043388581551395">"Званок з вібрацыяй"</string>
+    <string name="silent_mode_ring" msgid="8592241816194074353">"Званок укл."</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Выключэнне..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Планшэт будзе адключаны."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ваш тэлефон будзе выключаны."</string>
-    <!-- outdated translation 6656441286856415014 -->     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Адключыць прыладу?"</string>
+    <string name="shutdown_confirm_question" msgid="2906544768881136183">"Закрыць?"</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"Апошнія"</string>
-    <!-- outdated translation 279702952298056674 -->     <string name="no_recent_tasks" msgid="8794906658732193473">"Няма апошніх прыкладанняў."</string>
+    <string name="no_recent_tasks" msgid="8794906658732193473">"Няма апошніх прыкладанняў."</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Параметры планшэта"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"Параметры тэлефона"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Блакіроўка экрана"</string>
@@ -157,16 +160,16 @@
     <string name="safeMode" msgid="2788228061547930246">"Бяспечны рэжым"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Сістэма Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Платныя паслугі"</string>
-    <!-- outdated translation 8193824940620517189 -->     <string name="permgroupdesc_costMoney" msgid="8596717365335027057">"Дазволіць прыкладанням рабіць рэчы, якія могуць каштаваць вам грошай."</string>
+    <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Рабіць справы, якія могуць каштаваць вам грошай."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Вашыя паведамленні"</string>
-    <!-- outdated translation 7045736972019211994 -->     <string name="permgroupdesc_messages" msgid="7821999071003699236">"Чытайце і пішыце вашыя паведамленні электроннай пошты, SMS і г. д."</string>
+    <string name="permgroupdesc_messages" msgid="7821999071003699236">"Счытваць і запісваць вашы SMS-паведамленні, паведамленні электроннай пошты і іншыя паведамленні."</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Вашая персанальная інфармацыя"</string>
     <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Прамы доступ да кантактаў і календара, якія захоўваюцца на планшэце."</string>
     <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Прамы доступ да кантактаў і календара, захаваных на тэлефоне."</string>
     <string name="permgrouplab_location" msgid="635149742436692049">"Ваша месцазнаходжанне"</string>
-    <string name="permgroupdesc_location" msgid="2430258821648348660">"Кантралюйце сваё фізічнае месцазнаходжанне"</string>
+    <string name="permgroupdesc_location" msgid="5704679763124170100">"Кантраляваць сваё фізічнае месцазнаходжанне."</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"Сеткавая сувязь"</string>
-    <!-- outdated translation 5035763698958415998 -->     <string name="permgroupdesc_network" msgid="4917593670797570584">"Дазволіць прыкладанням атрымліваць доступ да розных функцый сеткі."</string>
+    <string name="permgroupdesc_network" msgid="4478299413241861987">"Доступ да розных функцый сеткі."</string>
     <string name="permgrouplab_accounts" msgid="3359646291125325519">"Вашыя ўліковыя запісы"</string>
     <string name="permgroupdesc_accounts" msgid="4948732641827091312">"Доступ да дзеючых уліковых запісаў."</string>
     <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Кіраванне апаратным забеспячэннем"</string>
@@ -176,352 +179,360 @@
     <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Сістэмныя інструменты"</string>
     <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Ніжні ўзровень доступу і кіравання сістэмай."</string>
     <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Сродкі распрацоўкі"</string>
-    <!-- outdated translation 9056431193893809814 -->     <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"Функцыі, патрэбныя толькі для распрацоўшчыкаў прыкладанняў."</string>
+    <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"Функцыi, патрэбныя толькі для распрацоўшчыкаў прыкладанняў."</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Сховішча"</string>
     <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Атрымаць доступ да USB-назапашвальнiка."</string>
     <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Доступ да SD-карты."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"адключаць ці змяняць радок стану"</string>
-    <!-- outdated translation 1365473595331989732 -->     <string name="permdesc_statusBar" msgid="8434669549504290975">"Дазваляе прыкладанням адключаць радок стану або дадаваць і выдаляць сістэмныя значкі."</string>
+    <string name="permdesc_statusBar" msgid="8434669549504290975">"Дазваляе прыкладанням адключаць радок стану або дадаваць і выдаляць сістэмныя значкі."</string>
     <string name="permlab_statusBarService" msgid="7247281911387931485">"радок стану"</string>
-    <!-- outdated translation 4097605867643520920 -->     <string name="permdesc_statusBarService" msgid="716113660795976060">"Дазваляе прыкладанням быць радком стану."</string>
+    <string name="permdesc_statusBarService" msgid="716113660795976060">"Дазваляе прыкладанням быць радком стану."</string>
     <string name="permlab_expandStatusBar" msgid="1148198785937489264">"разгарнуць/згарнуць радок стану"</string>
-    <!-- outdated translation 7088604400110768665 -->     <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Дазваляе прыкладанням разгортваць або згортваць панэль стану."</string>
+    <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Дазваляе прыкладанню разгортваць ці згортваць радок стану."</string>
     <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"перахапляць выходныя выклікі"</string>
-    <!-- outdated translation 2228988201852654461 -->     <string name="permdesc_processOutgoingCalls" msgid="1152111671618301044">"Дазваляе прыкладанням апрацоўваць выходныя выклікі і змяняць набіраны нумар. Шкоднасныя прыкладанні могуць адсочваць, перанакіроўваць ці забараняць выходныя выклікі."</string>
+    <string name="permdesc_processOutgoingCalls" msgid="1152111671618301044">"Дазваляе прыкладанням апрацоўваць выходныя выклікі і змяняць набіраны нумар. Шкоднасныя прыкладаннi могуць адсочваць, перанакіроўваць ці прадухіляць выходныя выклікі."</string>
     <string name="permlab_receiveSms" msgid="2697628268086208535">"атрымліваць SMS"</string>
-    <!-- outdated translation 6298292335965966117 -->     <string name="permdesc_receiveSms" msgid="8107887121893611793">"Дазваляе прыкладанням атрымліваць і апрацоўваць SMS. Шкоднасныя прыкладанні могуць адсочваць вашыя паведамленні або выдаляць іх, не паказваючы вам."</string>
+    <string name="permdesc_receiveSms" msgid="8107887121893611793">"Дазваляе прыкладанням атрымліваць і апрацоўваць SMS-паведамленні. Шкоднасныя прыкладанні могуць адсочваць вашыя паведамленні або выдаляць іх, не паказваючы вам."</string>
     <string name="permlab_receiveMms" msgid="8894700916188083287">"атрымліваць MMS"</string>
-    <!-- outdated translation 4563346832000174373 -->     <string name="permdesc_receiveMms" msgid="1424805308566612086">"Дазваляе прыкладанням атрымліваць і апрацоўваць паведамленні MMS. Шкоднасныя прыкладанні могуць адсочваць вашыя паведамленні або выдаляць іх без вашага ведама."</string>
+    <string name="permdesc_receiveMms" msgid="1424805308566612086">"Дазваляе прыкладанням атрымліваць і апрацоўваць MMS-паведамленні. Шкоднасныя прыкладанні могуць адсочваць вашы паведамленні або выдаляць іх, не паказваючы вам."</string>
     <string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"атрымліваць экстраныя трансляцыі"</string>
-    <!-- outdated translation 7118393393716546131 -->     <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Дазваляе прыкладанням атрымліваць і апрацоўваць экстраныя шырокавяшчальныя паведамленні. Гэты дазвол даступны толькі для сістэмных прыкладанняў."</string>
+    <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Дазваляе прыкладанням атрымліваць і апрацоўваць экстраныя паведамленні. Гэты дазвол даступны толькі для сістэмных прыкладанняў."</string>
     <string name="permlab_sendSms" msgid="5600830612147671529">"адпраўляць SMS"</string>
-    <!-- outdated translation 1946540351763502120 -->     <string name="permdesc_sendSms" msgid="906546667507626156">"Дазваляе прыкладанням адпраўляць SMS. Шкоднасныя прыкладанні могуць траціць вашыя грошы шляхам адпраўкі паведамленняў без пацверджання карыстальніка."</string>
+    <string name="permdesc_sendSms" msgid="906546667507626156">"Дазваляе прыкладанням дасылаць SMS-паведамленні. Шкоднасныя прыкладанні могуць каштаваць вам грошай з-за адпраўкі паведамленняў без вашага пацвярджэння."</string>
     <string name="permlab_sendSmsNoConfirmation" msgid="4781483105951730228">"адпраўляць SMS-паведамленні без пацверджання"</string>
-    <!-- outdated translation 4477752891276276168 -->     <string name="permdesc_sendSmsNoConfirmation" msgid="3437759207020400204">"Дазваляе прыкладанням адпраўляць SMS. Шкоднасныя прыкладанні могуць спісваць вашыя грошы, адпраўляючы паведамленні без вашага пацверджання."</string>
+    <string name="permdesc_sendSmsNoConfirmation" msgid="3437759207020400204">"Дазваляе прыкладанню дасылаць SMS-паведамленні. Шкоднасныя прыкладанні могуць каштаваць вам грошай з-за адпраўкі паведамленняў без вашага пацверджання."</string>
     <string name="permlab_readSms" msgid="4085333708122372256">"чытаць SMS або MMS"</string>
-    <!-- outdated translation 5836710350295631545 -->     <string name="permdesc_readSms" product="tablet" msgid="2341692916884515613">"Дазваляе прыкладанням чытаць SMS, якія захоўваюцца на планшэце ці на SIM-карце. Шкоднасныя прыкладанні могуць чытаць вашыя канфідэнцыйныя паведамленні."</string>
-    <!-- outdated translation 5836710350295631545 -->     <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Дазваляе прыкладанням чытаць SMS, якія захоўваюцца на планшэце ці на SIM-карце. Шкоднасныя прыкладанні могуць чытаць вашыя канфідэнцыйныя паведамленні."</string>
+    <string name="permdesc_readSms" product="tablet" msgid="2341692916884515613">"Дазваляе прыкладанням чытаць SMS-паведамленні, якія захоўваюцца на планшэце ці SIM-карце. Шкоднасныя прыкладанні могуць чытаць вашы канфідэнцыйныя паведамленні."</string>
+    <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Дазваляе прыкладанню счытваць SMS-паведамленні, якія захоўваюцца ў тэлефоне або на SIM-карце. Шкоднасныя прыкладанні могуць чытаць вашы канфідэнцыйныя паведамленні."</string>
     <string name="permlab_writeSms" msgid="6881122575154940744">"рэдагаваць SMS ці MMS"</string>
-    <!-- outdated translation 5332124772918835437 -->     <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Дазваляе прыкладанню запіс ў SMS паведамленнях, якія захоўваюцца на планшэце ці на SIM-карце. Шкоднасныя прыкладанні могуць выдаляць вашыя паведамленні."</string>
-    <!-- outdated translation 5332124772918835437 -->     <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Дазваляе прыкладанню запіс ў SMS паведамленнях, якія захоўваюцца на планшэце ці на SIM-карце. Шкоднасныя прыкладанні могуць выдаляць вашыя паведамленні."</string>
+    <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Дазваляе прыкладанню запісваць дадзеныя ў SMS-паведамленні, якія захоўваюцца на планшэце або на SIM-карце. Шкоднасныя прыкладанні могуць выдаляць вашы паведамленні."</string>
+    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Дазваляе прыкладанням запісваць дадзеныя ў SMS-паведамленні, якія захоўваюцца ў тэлефоне або на SIM-карце. Шкоднасныя прыкладанні могуць выдаляць вашы паведамленні."</string>
     <string name="permlab_receiveWapPush" msgid="8258226427716551388">"атрымліваць WAP"</string>
-    <!-- outdated translation 5979623826128082171 -->     <string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Дазваляе прыкладанням атрымліваць і апрацоўваць WAP-паведамленні. Шкоднасныя прыкладанні могуць адсочваць вашыя паведамленні або выдаляць іх, не паказваючы вам."</string>
-    <!-- outdated translation 5005277531132573353 -->     <string name="permlab_getTasks" msgid="6466095396623933906">"атрымліваць запушчаныя прыкладанні"</string>
-    <!-- outdated translation 7048711358713443341 -->     <string name="permdesc_getTasks" msgid="6608159250520381359">"Дазваляе прыкладанням атрымліваць інфармацыю аб бягучых і нядаўна запушчаных задачах. Можа дазволіць шкоднасным прыкладаннм выяўляць асабістую інфармацыю аб іншых прыкладаннях."</string>
-    <!-- outdated translation 5669588525059921549 -->     <string name="permlab_reorderTasks" msgid="2018575526934422779">"змяняць парадак запуску прыкладанняў"</string>
-    <!-- outdated translation 126252774270522835 -->     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дазваляе прыкладанням перамяшчаць задачы на ​​пярэдні план і ў фон. Шкоднасныя прыкладанні могуць прымусова перамясціць сябе на ​​пярэдні план без вашага кантролю."</string>
-    <!-- outdated translation 4802740047161700683 -->     <string name="permlab_removeTasks" msgid="6821513401870377403">"спыненне запушчаных прыкладанняў"</string>
-    <!-- outdated translation 2000332928514575461 -->     <string name="permdesc_removeTasks" msgid="1000226123143185094">"Дазваляе прыкладанням выдаляць задачы і спыняць адпаведныя прыкладанні. Шкоднасныя прыкладаннi могуць паўплываць на функцыянаванне іншых прыкладанняў."</string>
-    <!-- outdated translation 4339730312925176742 -->     <string name="permlab_setDebugApp" msgid="3022107198686584052">"уключаць адладку прыкладанняў"</string>
-    <!-- outdated translation 5584310661711990702 -->     <string name="permdesc_setDebugApp" msgid="6215654419903651172">"Дазваляе прыкладанням уключаць адладку іншых прыкладанняў. Шкоднасныя прыкладаннi могуць карыстацца гэтым, каб спыняць іншыя прыкладанні."</string>
+    <string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Дазваляе прыкладанням атрымліваць і апрацоўваць WAP-паведамленні. Шкоднасныя прыкладанні могуць адсочваць вашы паведамленні або выдаляць іх, не паказваючы вам."</string>
+    <string name="permlab_getTasks" msgid="6466095396623933906">"атрымаць запушчаныя прыкладанні"</string>
+    <string name="permdesc_getTasks" msgid="6608159250520381359">"Дазваляе прыкладанням атрымліваць інфармацыю пра бягучыя і нядаўна запушчаныя заданнi. Шкоднасныя прыкладанні могуць атрымліваць асабістую інфармацыю пра іншыя прыкладаннi."</string>
+    <string name="permlab_reorderTasks" msgid="2018575526934422779">"змяніць парадак запушчаных прыкладанняў"</string>
+    <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дазваляе прыкладанням перамяшчаць заданні на ​​пярэдні план і фон. Шкоднасныя прыкладанні могуць прымусова рабіць сябе асноўнымі без вашага ведама."</string>
+    <string name="permlab_removeTasks" msgid="6821513401870377403">"спыніць запушчаныя прыкладанні"</string>
+    <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дазваляе прыкладанням выдаляць заданні і спыняць прыкладанні, якія іх выкарыстоўваюць. Шкоднасныя прыкладаннi могуць перашкодзiць працы іншых прыкладанняў."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"усталяваць сумяшчальнасць экранаў"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Дазваляе прыкладанню кіраваць рэжымам сумяшчальнасці экранаў іншых прыкладанняў. Шкоднаснае ПЗ можа перашкодзiць працы іншых прыкладанняў."</string>
+    <string name="permlab_setDebugApp" msgid="3022107198686584052">"уключыць адладку прыкладання"</string>
+    <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дазваляе прыкладанням уключаць адладку для іншага прыкладання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб спыняць іншыя прыкладанні."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"змяняць налады карыстальніцкага інтэрфейса"</string>
-    <!-- outdated translation 3465121501528064399 -->     <string name="permdesc_changeConfiguration" msgid="4104052649900380324">"Дазваляе прыкладанням змяняць бягучую канфігурацыю, напрыклад мову i агульны памер шрыфта."</string>
+    <string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Дазваляе прыкладанням змяняць бягучую канфігурацыю, напрыклад мову цi агульны памер шрыфта."</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"дазваляць рэжым \"У аўтамабілі\""</string>
-    <!-- outdated translation 5673461159384850628 -->     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Дазваляе прыкладанням уключаць рэжым \"У аўтамабілі\"."</string>
+    <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Дазваляе прыкладанню ўключаць рэжым гучнай сувязi."</string>
     <string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"выдаліць фонавыя працэсы"</string>
-    <!-- outdated translation 2908829602869383753 -->     <string name="permdesc_killBackgroundProcesses" msgid="931129103262126617">"Дазваляе прыкладанням спыняць фонавыя працэсы іншых прыкладанняў, нават калі памяці дастаткова."</string>
-    <!-- outdated translation 1447830113260156236 -->     <string name="permlab_forceStopPackages" msgid="2329627428832067700">"прымусова спыняць іншыя прыкладанні"</string>
-    <!-- outdated translation 7263036616161367402 -->     <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Дазваляе прыкладанню прымусова спыняць іншыя прыкладанні."</string>
-    <!-- outdated translation 1804196839880393631 -->     <string name="permlab_forceBack" msgid="652935204072584616">"прымусова закрываць прыкладанні"</string>
-    <!-- outdated translation 6534109744159919013 -->     <string name="permdesc_forceBack" msgid="3892295830419513623">"Дазваляе прыкладанням прымусова спыняць усе актыўныя працэсы і працягваць працу. Ніколі не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_killBackgroundProcesses" msgid="931129103262126617">"Дазваляе прыкладанням спыняць фонавыя працэсы іншых прыкладанняў, нават калі памяці дастаткова."</string>
+    <string name="permlab_forceStopPackages" msgid="2329627428832067700">"прымусова спыніць іншыя прыкладанні"</string>
+    <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Дазваляе прыкладанням прымусова спыняць іншыя прыкладанні."</string>
+    <string name="permlab_forceBack" msgid="652935204072584616">"прымусова закрыць прыкладанне"</string>
+    <string name="permdesc_forceBack" msgid="3892295830419513623">"Дазваляе прыкладанням прымусова закрываць любы асноўны працэс. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_dump" msgid="1681799862438954752">"атрымліваць унутраны стан сістэмы"</string>
-    <!-- outdated translation 2198776174276275220 -->     <string name="permdesc_dump" msgid="1778299088692290329">"Дазваляе прыкладанням атрымліваць інфармацыю аб унутраным стане сістэмы. Шкодныя прыкладанні могуць атрымлiваць шырокі спектр прыватнай і абараняемай інфармацыі, якая звычайна ніколі ім не патрабуецца."</string>
+    <string name="permdesc_dump" msgid="1778299088692290329">"Дазваляе прыкладанням атрымліваць інфармацыю аб унутраным стане сістэмы. Шкоднасныя прыкладанні могуць атрымліваць шырокі спектр прыватных дадзеных і дадзеных, прызначаных для забеспячэння бяспекі інфармацыі, якія звычайна ім не патрэбны."</string>
     <string name="permlab_retrieve_window_content" msgid="8022588608994589938">"атрыманне зместу экрана"</string>
-    <!-- outdated translation 3390962289797156152 -->     <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Дазваляе прыкладанням атрымліваць змест актыўнага акна. Шкоднасныя прыкладаннi могуць атрымаць увесь змест акна і вывучыць увесь яго тэкст, акрамя пароляў."</string>
+    <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Дазваляе прыкладанням атрымліваць змесціва актыўнага акна. Шкоднасныя прыкладанні могуць атрымліваць усё змесціва акна і разглядаць увесь яго тэкст, акрамя пароляў."</string>
     <string name="permlab_shutdown" msgid="7185747824038909016">"частковае адключэнне"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Спыняе дзейнасць менеджэра. Не выконвае поўнае адключэнне."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"прадухіляць пераключэнне прыкладанняў"</string>
-    <!-- outdated translation 3857886086919033794 -->     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Прадухіляе карыстальнікаў ад пераходу на іншае прыкладанне."</string>
-    <!-- outdated translation 7811586187574696296 -->     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"адсочваць усе запускі прыкладанняў і кіраваць iмi"</string>
-    <!-- outdated translation 2149363027173451218 -->     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дазваляе прыкладанню сачыць за тым, як сістэма запускае працэсы, i кiраваць гэтым дзеяннем. Шкоднасныя прыкладанні могуць цалкам негатыўна паўсплываць на сістэму. Гэты дазвол неабходны толькі для распрацоўкі, не для звычайнага выкарыстання."</string>
+    <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Не дазваляе карыстальніку пераходзіць да іншага прыкладання."</string>
+    <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"адсочваць і кантраляваць запуск усіх прыкладанняў"</string>
+    <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дазваляе прыкладанню сачыць і кантраляваць, як сістэма запускае працэсы. Шкоднасныя прыкладанні могуць цалкам парушыць працу сістэмы. Гэты дазвол патрэбны толькі для распрацоўкі, ніколі для звычайнага выкарыстання."</string>
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"трансляваць паведамленні аб выдаленні пакетаў"</string>
-    <!-- outdated translation 3453286591439891260 -->     <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Дазваляе прыкладанням трансліраваць апавяшчэнне аб тым, што пакет прыкладання быў выдалены. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб спыніць любое іншае запушчанае прыкладанне."</string>
+    <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Дазваляе прыкладанням перадаваць апавяшчэнне, што пакет прыкладанняў быў выдалены. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб спыняць любыя іншыя запушчаныя прыкладанні."</string>
     <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"перасылаць трансляцыі, атрыманыя па SMS"</string>
-    <!-- outdated translation 9122419277306740155 -->     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дазваляе прыкладанню трансляваць апавяшчэнне, што паведамленне SMS атрыманае. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб падрабляць уваходныя паведамленні SMS."</string>
+    <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дазваляе прыкладанням перадаваць апавяшчэнне пра атрыманне SMS-паведамлення. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб падрабляць уваходныя SMS-паведамленні."</string>
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"пасылаць сігнал WAP-PUSH-received"</string>
-    <!-- outdated translation 3955303669461378091 -->     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дазваляе прыкладанням трансляваць апавяшчэнне аб атрыманні паведамлення WAP PUSH. Шкоднасныя прыкладаннi могуць карыстацца гэтым, каб падрабляць атрыманне MMS-паведамленняў ці моўчкі мяняць змест любых вэб-старонак на шкодны."</string>
+    <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дазваляе прыкладанням перадаваць апавяшчэнне, што паведамленне WAP PUSH не было атрымана. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб падрабляць атрыманне MMS-паведамлення або непрыкметна замяняць змесціва любой вэб-старонкі на шкоднасную версiю."</string>
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"абмяжоўваць колькасць запушчаных працэсаў"</string>
-    <!-- outdated translation 7824786028557379539 -->     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дазваляе прыкладанням кантраляваць максімальную колькасць працэсаў, якія будуць працаваць. Ніколі не патрабуецца для звычайных прыкладанняў."</string>
-    <!-- outdated translation 5342837862439543783 -->     <string name="permlab_setAlwaysFinish" msgid="238828158465736054">"закрываць усе фонавыя прыкладанні"</string>
-    <!-- outdated translation 8773936403987091620 -->     <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Дазваляе прыкладанню кантраляваць завяршэнне дзеянняў падчас іх пераходу ў фон. Ніколі не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дазваляе прыкладанням кантраляваць максімальную колькасць запушчаных працэсаў. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permlab_setAlwaysFinish" msgid="238828158465736054">"закрывае ўсе фонавыя прыкладанні"</string>
+    <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Дазваляе прыкладанням кантраляваць, ці будуць працэсы заўсёды завяршацца, як толькі яны пераходзяць у фонавы рэжым. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_batteryStats" msgid="7863923071360031652">"змяняць статыстыку батарэі"</string>
-    <!-- outdated translation 5847319823772230560 -->     <string name="permdesc_batteryStats" msgid="6835186932305744068">"Дазваляе мяняць сабраную статыстыку акумулятара. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+    <string name="permdesc_batteryStats" msgid="6835186932305744068">"Дазваляе прыкладанням змяняць сабраную статыстыку акумулятара. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="permlab_backup" msgid="470013022865453920">"кантраляваць рэзервовае капіяванне і аднаўленне сістэмы"</string>
-    <!-- outdated translation 4837493065154256525 -->     <string name="permdesc_backup" msgid="6912230525140589891">"Дазваляе прыкладанням кантраляваць механізм рэзервовага капіявання і аднаўлення сістэмы. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+    <string name="permdesc_backup" msgid="6912230525140589891">"Дазваляе прыкладанням кантраляваць рэзервовае капіяванне сістэмы і механізм аднаўлення. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"пацверджанне поўнага рэзервовага капіявання або аднаўлення"</string>
-    <!-- outdated translation 9005017754175897954 -->     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Дазваляе прыкладанням запускаць інтэрфейс пацверджання поўнага рэзервовага капіявання. Выкарыстоўваецца не ўсімі прыкладаннямі."</string>
+    <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Дазваляе прыкладанням запускаць поўны інтэрфейс карыстальніка пацвярджэння рэзервавання. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"паказваць несанкцыянаваныя вокны"</string>
-    <!-- outdated translation 5895082268284998469 -->     <string name="permdesc_internalSystemWindow" msgid="6510907081810231374">"Дазваляе ствараць вокны, прызначаныя для ўнутранай сістэмы карыстальніцкага інтэрфейса. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+    <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Дазваляе прыкладанням ствараць вокны, прызначаныя для выкарыстання ўнутраным інтэрфейсам карыстальніка сістэмы. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"паказваць абвесткі стану сістэмы"</string>
-    <!-- outdated translation 2884149573672821318 -->     <string name="permdesc_systemAlertWindow" msgid="8507863469978066409">"Дазваляе прыкладанню паказваць вокны сiстэмных паведамленняў. Шкоднасныя прыкладанні могуць заняць увесь экран."</string>
+    <string name="permdesc_systemAlertWindow" msgid="8507863469978066409">"Дазваляе прыкладанням паказваць вокны апавяшчэння сістэмы. Шкоднасныя прыкладанні могуць захоплiваць увесь экран."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"зменяць агульную хуткасць анімацыі"</string>
-    <!-- outdated translation 7181522138912391988 -->     <string name="permdesc_setAnimationScale" msgid="6505093307223395456">"Дазваляе прыкладанням у любы час мяняць агульную хуткасць анімацыі (хутчэй ці павольней)."</string>
-    <!-- outdated translation 17124341698093865 -->     <string name="permlab_manageAppTokens" msgid="1286505717050121370">"кіраваць меткамі прыкладанняў"</string>
-    <!-- outdated translation 977127907524195988 -->     <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Дазваляе прыкладанням ствараць уласныя квіткі і кіраваць імі, у абыход нармальнага Z-упарадкавання. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Дазваляе прыкладанням у любы час змяняць агульную хуткасць анімацыі (хутчэй ці павольней)."</string>
+    <string name="permlab_manageAppTokens" msgid="1286505717050121370">"кіраваць ключамі прыкладання"</string>
+    <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Дазваляе прыкладанням ствараць  сваімі ўласнымі ключамі, абыходзячы іх звычайны Z-парадак. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_injectEvents" msgid="1378746584023586600">"націскаць клавішы і кнопкі кіравання"</string>
-    <!-- outdated translation 7200014808195664505 -->     <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Дазваляе прыкладанням ажыццяўляць свае ўласныя працэсы ўводу (націску клавіш і г. д.) для іншых прыкладанняў. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб атрымаць кантроль над планшэтам."</string>
-    <!-- outdated translation 7200014808195664505 -->     <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Дазваляе прыкладанням ажыццяўляць свае ўласныя працэсы ўводу (націску клавіш і г. д.) для іншых прыкладанняў. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб атрымаць кантроль над планшэтам."</string>
+    <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Дазваляе прыкладанням ажыццяўляць свае ўласныя падзеі ўводу (націску клавіш і г.д.) для іншых прыкладанняў. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб захапіць кіраванне планшэтам."</string>
+    <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Дазваляе прыкладанню ажыццяўляць свае ўласныя падзеі ўводу (націску клавіш і г. д.) для іншых прыкладанняў. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб захапіць кіраванне тэлефонам."</string>
     <string name="permlab_readInputState" msgid="469428900041249234">"запісваць, што вы друкуеце, і дзеянні, якія вы прадпрымаеце"</string>
-    <!-- outdated translation 5132879321450325445 -->     <string name="permdesc_readInputState" msgid="8387754901688728043">"Дазваляе прыкладанням праглядаць клавішы, якія вы націскаеце, нават пры ўзаемадзеянні з іншым прыкладаннем (напрыклад, пры ўводзе пароля). Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_readInputState" msgid="8387754901688728043">"Дазваляе прыкладанням адсочваць клавішы, якія вы націскаеце, нават падчас узаемадзеяння з іншым прыкладаннем (напрыклад, пры ўводзе пароля). Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"звязацца з метадам уводу"</string>
-    <!-- outdated translation 3734838321027317228 -->     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дазваляе ўладальніку звязвацца з інтэрфейсам верхняга ўзроўню метадам уводу. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню метада ўводу. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"звязаць з тэкставай службай"</string>
-    <!-- outdated translation 172508880651909350 -->     <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дазваляе ўладальніку звязвацца з інтэрфейсам верхняга ўзроўню тэкставай паслугі (напрыклад, SpellCheckerService). Ніколі не патрабуецца звычайным прыкладанням."</string>
+    <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню тэкставай паслугі (напрыклад, SpellCheckerService). Ніколі не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"звязвацца з VPN сэрвісам"</string>
-    <!-- outdated translation 6011554199384584151 -->     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дазваляе ўладальніку звязвацца з інтэрфейсам VPN службы вышэйшага ўзроўню. Не патрэбна для звычайных праграм."</string>
+    <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дазваляе ўладальніку звязвацца з інтэрфейсам службы VPN вышэйшага ўзроўню. Не патрэбна для звычайных прыкладанняў."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"прывязаць да шпалер"</string>
-    <!-- outdated translation 5287754520361915347 -->     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дазваляе ўладальніку ўсталёўваць прывязку да інтэрфейсу шпалер верхняга ўзроўню. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дазваляе ўладальніку ўсталёўваць прывязку да інтэрфейсу шпалер верхняга ўзроўню. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прывязаць да службы віджэту"</string>
-    <!-- outdated translation 2930855984822926963 -->     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дазваляе ўладальніку прывязаць верхні ўзровень інтэрфейсу службы віджэта. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню службы віджэта. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"узаемадзейнічаць з адміністратарам прылады"</string>
-    <!-- outdated translation 8714424333082216979 -->     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дазваляе ўладальніку адпраўляць намеры да адміністратара прылады. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дазваляе ўладальніку адпраўляць намеры да адміністратара прылады. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_setOrientation" msgid="3365947717163866844">"змяняць арыентацыю экрана"</string>
-    <!-- outdated translation 6335814461615851863 -->     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Дазваляе прыкладанням мяняць арыентацыю экрана ў любы час. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_setOrientation" msgid="3046126619316671476">"Дазваляе прыкладанням змяняць паварот экрана ў любы час. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_setPointerSpeed" msgid="9175371613322562934">"змена хутк. перамяшч. ўказ."</string>
-    <!-- outdated translation 137436038503379864 -->     <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Дазваляе прыкладанням у любы момант мяняць хуткасць перамяшчэння ўказальніка мышы ці трэкпаду. Не патрабуецца для звычайных прыкладанняў."</string>
-    <!-- outdated translation 4255467255488653854 -->     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"адпраўляць сігналы Linux да прыкладанняў"</string>
-    <!-- outdated translation 3565530463215015289 -->     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Дазваляе прыкладанням запытваць адпраўку прадстаўленага сігналу да ўсіх пастаянных працэсаў."</string>
-    <!-- outdated translation 8659652042401085862 -->     <string name="permlab_persistentActivity" msgid="8841113627955563938">"прымусіць прыкладанне працаваць заўсёды"</string>
-    <!-- outdated translation 5037199778265006008 -->     <string name="permdesc_persistentActivity" msgid="4909910271316074418">"Дазваляе прыкладанням рабіць свае часткі ўстойлівымі, каб сістэма не магла выкарыстоўваць іх для іншых прыкладанняў."</string>
-    <!-- outdated translation 3343439331576348805 -->     <string name="permlab_deletePackages" msgid="184385129537705938">"выдаляць прыкладанні"</string>
-    <!-- outdated translation 3634943677518723314 -->     <string name="permdesc_deletePackages" msgid="7411480275167205081">"Дазваляе прыкладанням выдаляць пакеты Android. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб выдаляць важныя прыкладанні."</string>
-    <!-- outdated translation 2192134353540277878 -->     <string name="permlab_clearAppUserData" msgid="274109191845842756">"выдаляць дадзеныя іншых прыкладанняў"</string>
-    <!-- outdated translation 7546345080434325456 -->     <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Дазваляе прыкладанням выдаляць дадзеныя карыстальніка."</string>
-    <!-- outdated translation 1518556602634276725 -->     <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"выдаляць кэш іншых прыкладанняў"</string>
-    <!-- outdated translation 2283074077168165971 -->     <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Дазваляе прыкладанням выдаляць файлы кэша."</string>
-    <!-- outdated translation 4799785352306641460 -->     <string name="permlab_getPackageSize" msgid="7472921768357981986">"мераць месца для захоўвання прыкладання"</string>
-    <!-- outdated translation 5557253039670753437 -->     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Дазваляе прыкладанням атрымліваць свой код, дадзеныя і аб\'ём кэш-памяці"</string>
-    <!-- outdated translation 335800214119051089 -->     <string name="permlab_installPackages" msgid="2199128482820306924">"непасрэдна ўсталёўваць прыкладанні"</string>
-    <!-- outdated translation 526669220850066132 -->     <string name="permdesc_installPackages" msgid="5628530972548071284">"Дазваляе прыкладанням усталёўваць новыя або абноўленыя пакеты Android. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дадаваць новыя прыкладанні з дазволамі высокага ўзроўню."</string>
-    <!-- outdated translation 4747698311163766540 -->     <string name="permlab_clearAppCache" msgid="7487279391723526815">"выдаляць усе дадзеныя кэша прыкладання"</string>
-    <!-- outdated translation 3097119797652477973 -->     <string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Дазваляе прыкладанню вызваліць прастору на планшэце, выдаліўшы файлы з каталогу кэша прыкладання. Доступ да сістэмных працэсаў звычайна вельмі абмежаваны."</string>
-    <!-- outdated translation 3097119797652477973 -->     <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Дазваляе прыкладанню вызваліць прастору на планшэце, выдаліўшы файлы з каталогу кэша прыкладання. Доступ да сістэмных працэсаў звычайна вельмі абмежаваны."</string>
-    <!-- outdated translation 728454979946503926 -->     <string name="permlab_movePackage" msgid="3289890271645921411">"Перамяшчэнне рэсурсаў прыкладання"</string>
-    <!-- outdated translation 6323049291923925277 -->     <string name="permdesc_movePackage" msgid="319562217778244524">"Дазваляе прыкладанню перамяшчаць рэсурсы прыкладання з унутранай памяці на знешні носьбіт і наадварот."</string>
+    <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Дазваляе прыкладанням змяняць хуткасць курсору мышы або трэкпада ў любы час. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"адправіць сігналы Linux да прыкладанняў"</string>
+    <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Дазваляе прыкладанням запытваць адпраўку падаваемага сігнала для ўсiх пастаянных працэсаў."</string>
+    <string name="permlab_persistentActivity" msgid="8841113627955563938">"прымусіць прыкладанне працаваць заўсёды"</string>
+    <string name="permdesc_persistentActivity" msgid="4909910271316074418">"Дазваляе прыкладанням рабіць свае часткі пастаяннымі, каб сістэма не магла выкарыстоўваць iх для іншых прыкладанняў."</string>
+    <string name="permlab_deletePackages" msgid="184385129537705938">"выдаліць прыкладанні"</string>
+    <string name="permdesc_deletePackages" msgid="7411480275167205081">"Дазваляе прыкладанню выдаляць пакеты Android. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб выдаляць важныя прыкладанні."</string>
+    <string name="permlab_clearAppUserData" msgid="274109191845842756">"выдаліць дадзеныя іншых прыкладанняў"</string>
+    <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Дазваляе прыкладанням выдаляць дадзеныя карыстальніка."</string>
+    <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"выдаліць кэш-памяць іншых прыкладанняў"</string>
+    <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Дазваляе прыкладанню выдаляць файлы кэш-памяці."</string>
+    <string name="permlab_getPackageSize" msgid="7472921768357981986">"вымерыць прастору для захоўвання прыкладання"</string>
+    <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Дазваляе прыкладанням атрымліваць яго код, дадзеныя і аб\'ём кэш-памяці"</string>
+    <string name="permlab_installPackages" msgid="2199128482820306924">"усталяваць прыкладанні непасрэдна"</string>
+    <string name="permdesc_installPackages" msgid="5628530972548071284">"Дазваляе прыкладанням ксталёўваць новыя або абноўленыя пакеты Android. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дадаваць новыя прыкладаннi з дазволамі адвольнай ступені."</string>
+    <string name="permlab_clearAppCache" msgid="7487279391723526815">"выдаліць усе дадзеныя з кэш-памяці прыкладання"</string>
+    <string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Дазваляе прыкладанню вызваляць памяць планшэту, выдаляючы файлы ў каталогу кэш-памяці прыкладання. Як правіла, доступ да сістэмных працэсаў вельмі абмежаваны."</string>
+    <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Дазваляе прыкладанням вызваляць памяць тэлефона, выдаляючы файлы з каталогу кэш-памяці прыкладання. Доступ да сістэмных працэсаў, як правіла, вельмі абмежаваны."</string>
+    <string name="permlab_movePackage" msgid="3289890271645921411">"перамясціць рэсурсы прыкладання"</string>
+    <string name="permdesc_movePackage" msgid="319562217778244524">"Дазваляе прыкладанням перамяшчаць рэсурсы прыкладання з унутраных на знешнія носьбіты і наадварот."</string>
     <string name="permlab_readLogs" msgid="6615778543198967614">"чытаць канфідэнцыйныя дадзеныя дзённiка"</string>
-    <!-- outdated translation 4077356893924755294 -->     <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Дазваляе прыкладанням чытаць розныя файлы журналаў сістэмы. Такiм чынам можна выявiць агульную інфармацыю аб тым, што вы робіце з планшэтам, якая патэнцыйна змяшчае асабістыя або канфiдэнцыйныя звесткi."</string>
-    <!-- outdated translation 4077356893924755294 -->     <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Дазваляе прыкладанням чытаць розныя файлы журналаў сістэмы. Такiм чынам можна выявiць агульную інфармацыю аб тым, што вы робіце з планшэтам, якая патэнцыйна змяшчае асабістыя або канфiдэнцыйныя звесткi."</string>
+    <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Дазваляе прыкладанням счытваць розныя файлы сiстэмнай гiсторыi. Такiм чынам, можна выявiць агульную інфармацыю пра тое, што вы робіце з планшэтам, у тым ліку, магчыма, асабістыя або канфiдэнцыйныя звесткi."</string>
+    <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Дазваляе прыкладанню счытваць розныя сістэмныя файлы гiсторый. Гэта дазваляе атрымліваць агульную інфармацыю аб тым, як выкарыстоўваецца тэлефон, у тым ліку, магчыма, асабістую або прыватную інфармацыю."</string>
+    <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"для прайгравання выкарыстоўваць любы мультымедыйны дэкодэр"</string>
+    <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Дазваляе прыкладанням выкарыстоўваць любы ўсталяваны iнструмент для мультымедыйнага дэкадавання, каб прайграць."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"чытаць/запісваць на дыягнастычныя рэсурсы"</string>
-    <!-- outdated translation 3121238373951637049 -->     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дазваляе прыкладанням счытваць і запісваць любы рэсурс, які належыць дыягнастычнай групе, напрыклад файлы распрацоўшчыка. Патэнцыйна гэта можа паўплываць на стабільнасць і бяспеку сістэмы. Гэта павінна выкарыстоўвацца ТОЛЬКІ для апаратнай дыягностыкі вытворцам або аператарам."</string>
-    <!-- outdated translation 79425198834329406 -->     <string name="permlab_changeComponentState" msgid="6335576775711095931">"уключаць або адключаць кампаненты прыкладання"</string>
-    <!-- outdated translation 4647419365510068321 -->     <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Дазваляе прыкладанню ўключаць ці адключаць кампанент іншага прыкладання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для адключэння важных магчымасцяў тэлефона. Трэба захоўваць асцярожнасць з гэтым дазволам, таму што гэта можа прывесці кампаненты прыкладання да непрыдатнасці, непаслядоўнасці або няўстойлівасці."</string>
-    <!-- outdated translation 4647419365510068321 -->     <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Дазваляе прыкладанню ўключаць ці адключаць кампанент іншага прыкладання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для адключэння важных магчымасцяў тэлефона. Трэба захоўваць асцярожнасць з гэтым дазволам, таму што гэта можа прывесці кампаненты прыкладання да непрыдатнасці, непаслядоўнасці або няўстойлівасці."</string>
-    <!-- outdated translation 3393305202145172005 -->     <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"выбіраць пажаданыя праграмы"</string>
-    <!-- outdated translation 760008293501937546 -->     <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Дазваляе прыкладанням змяняць вашы выбраныя прыкладанні. Гэта можа дазволіць шкоднасным прыкладанням незаўважна мяняць прыкладанні, якія запускаюцца, падмяняць існуючыя прыкладанні для збору вашых канфідэнцыйных дадзеных."</string>
+    <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дазваляе прыкладанням счытваць і запісваць любы рэсурс, які належыць дыягнастычнай групе, напрыклад файлы распрацоўшчыка ў тэчцы /dev. Патэнцыйна гэта можа паўплываць на стабільнасць і бяспеку сістэмы. Гэта павінна выкарыстоўвацца ТОЛЬКІ для апаратнай дыягностыкі вытворцам або аператарам."</string>
+    <string name="permlab_changeComponentState" msgid="6335576775711095931">"уключыць або адключыць кампаненты прыкладання"</string>
+    <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Дазваляе прыкладанням змяняць вызначэнне таго, будзе ўключаны кампанент іншага прыкладання ці не. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для адключэння важных магчымасцяў планшэта. З гэтым дазволам трэба быць уважлівым, бо можна прывесці кампаненты прыкладання ў непрыдатны, супярэчлівы або няўстойлівы стан."</string>
+    <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Дазваляе прыкладанням змяняць вызначэнне таго, будзе ўключаны кампанент іншага прыкладання ці не. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для адключэння важных магчымасцяў тэлефона. З гэтым дазволам трэба быць уважлівым, бо можна прывесці кампаненты прыкладання ў непрыдатны, супярэчлівы або няўстойлівы стан."</string>
+    <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"усталяваць пажаданыя прыкладанні"</string>
+    <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Дазваляе прыкладанням змяняць вашы пажаданыя прыкладанні. Шкоднасныя прыкладанні могуць непрыкметна змяняць запушчаныя прыкладанні, падмяняючы існуючыя прыкладанні, каб збiраць вашы асабістыя дадзеныя."</string>
     <string name="permlab_writeSettings" msgid="1365523497395143704">"змена глабальных параметраў сістэмы"</string>
-    <!-- outdated translation 838789419871034696 -->     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Дазваляе прыкладанням змяняць налады сістэмы. Шкодныя прыкладанні могуць пашкодзіць канфігурацыю сістэмы."</string>
+    <string name="permdesc_writeSettings" msgid="7775723441558907181">"Дазваляе прыкладаннем змяняць дадзеныя налад сістэмы. Шкоднасныя прыкладанні могуць пашкодзіць канфігурацыю вашай сістэмы."</string>
     <string name="permlab_writeSecureSettings" msgid="204676251876718288">"змяняць параметры бяспекі сістэмы"</string>
-    <!-- outdated translation 5497873143539034724 -->     <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Дазваляе прыкладанням мяняць параметры бяспекі сістэмы. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+    <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Дазваляе прыкладанням змяняць дадзеныя параметраў бяспекі сістэмы. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="permlab_writeGservices" msgid="2149426664226152185">"змяняць карту службаў Google"</string>
-    <!-- outdated translation 6602362746516676175 -->     <string name="permdesc_writeGservices" msgid="1287309437638380229">"Дазваляе прыкладанням змяняць карту службаў Google. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+    <string name="permdesc_writeGservices" msgid="1287309437638380229">"Дазваляе прыкладанням змяняць карту службаў Google. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"аўтаматычна запускаць пры загрузцы"</string>
-    <!-- outdated translation 7530977064379338199 -->     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Дазваляе прыкладанням запускаць саміх сябе, як толькі сістэма цалкам загрузіцца. Гэта можа зрабіць загрузку планшэта больш павольнай і дазволіць прыкладанню запаволіць увесь планшэт, заўсёды працуючы."</string>
-    <!-- outdated translation 7530977064379338199 -->     <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Дазваляе прыкладанням запускаць саміх сябе, як толькі сістэма цалкам загрузіцца. Гэта можа зрабіць загрузку планшэта больш павольнай і дазволіць прыкладанню запаволіць увесь планшэт, заўсёды працуючы."</string>
+    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Дазваляе прыкладанню самастойна запускацца, як толькі сістэма будзе цалкам загружана. Гэта можа павялічыць час запуску планшэту і дазволіць прыкладанню запаволіць увесь планшэт, прымушаючы яго працаваць заўсёды."</string>
+    <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Дазваляе прыкладанням самастойна запускацца, як толькі сістэма будзе цалкам запушчана. Гэта можа павялічыць час запуску тэлефону і дазволіць прыкладанню запаволіць увесь тэлефон, прымушаючы яго працаваць заўсёды."</string>
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"адпраўляць нетэрмiновую рассылку"</string>
-    <!-- outdated translation 6322249605930062595 -->     <string name="permdesc_broadcastSticky" product="tablet" msgid="1181582512022829259">"Дазваляе прыкладанням адпраўляць прыдаткі да трансляцый, якія застаюцца пасля заканчэння трансляцыі. Шкоднасныя прыкладанні могуць зрабіць работу планшэта павольнай або нестабільнай, прымушаючы яго выкарыстоўваць занадта вялікі аб\'ём памяці."</string>
-    <!-- outdated translation 6322249605930062595 -->     <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Дазваляе прыкладанням адпраўляць прыдаткі да трансляцый, якія застаюцца пасля заканчэння трансляцыі. Шкоднасныя прыкладанні могуць зрабіць работу планшэта павольнай або нестабільнай, прымушаючы яго выкарыстоўваць занадта вялікі аб\'ём памяці."</string>
+    <string name="permdesc_broadcastSticky" product="tablet" msgid="1181582512022829259">"Дазваляе прыкладанням дасылаць далейшыя звязаныя перадачы, якія застаюцца пасля заканчэння асноўнай перадачы. Шкоднасныя прыкладанні могуць зрабіць працу планшэта павольнай або няўстойлівай, прымушаючы яго выкарыстоўваць занадта шмат памяці."</string>
+    <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Дазваляе прыкладанню дасылаць далейшыя звязаныя перадачы, якія застаюцца пасля заканчэння асноўнай перадачы. Шкоднасныя прыкладанні могуць зрабіць працу тэлефона павольнай або няўстойлівай, прымушаючы яго выкарыстоўваць занадта шмат памяці."</string>
     <string name="permlab_readContacts" msgid="6219652189510218240">"чытаць кантактныя дадзеныя"</string>
-    <!-- outdated translation 7596158687301157686 -->     <string name="permdesc_readContacts" product="tablet" msgid="4028657556924039119">"Дазваляе прыкладанням счытваць усе кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб адпраўляць вашыя дадзеныя іншым асобам."</string>
-    <!-- outdated translation 7596158687301157686 -->     <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Дазваляе прыкладанням счытваць усе кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб адпраўляць вашыя дадзеныя іншым асобам."</string>
+    <string name="permdesc_readContacts" product="tablet" msgid="4028657556924039119">"Дазваляе прыкладанням счытваць усе кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб адпраўляць дадзеныя іншым людзям."</string>
+    <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Дазваляе прыкладанням счытваць усе кантакты (адрасы), якія захоўваюцца на вашым тэлефоне. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб адпраўляць дадзеныя іншым людзям."</string>
     <string name="permlab_writeContacts" msgid="644616215860933284">"запісваць кантактныя дадзеныя"</string>
-    <!-- outdated translation 7782689510038568495 -->     <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Дазваляе прыкладанням змяняць кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб сцерці або змяніць вашыя кантактныя дадзеныя."</string>
-    <!-- outdated translation 7782689510038568495 -->     <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Дазваляе прыкладанням змяняць кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб сцерці або змяніць вашыя кантактныя дадзеныя."</string>
+    <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Дазваляе прыкладанням змяняць кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэтую магчымасць для выдалення або змены кантактных дадзеных."</string>
+    <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Дазваляе прыкладанням змяняць кантакты (адрасы), якія захоўваюцца на вашым тэлефоне. Шкоднасныя прыкладанні могуць выкарыстоўваць гэту магчымасць для выдалення або змены кантактных дадзеных."</string>
     <string name="permlab_readProfile" msgid="6824681438529842282">"чытаць дадзеныя вашага профілю"</string>
-    <!-- outdated translation 6335739730324727203 -->     <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"Дазваляе прыкладанням счытваць персанальныя дадзеныя профілю, якія захоўваюцца на вашай прыладзе (напрыклад, вашыя імя і кантактную інфармацыю). Гэта азначае, што прыкладанне можа ідэнтыфікаваць вас і адправіць інфармацыю аб вашым профілі іншым асобам."</string>
+    <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"Дазваляе прыкладанням счытваць асабістую інфармацыю ў профілях, якая захоўваецца на вашай прыладзе, напрыклад, ваша імя і кантактную інфармацыю. Гэта азначае, што прыкладанне можа ідэнтыфікаваць вас і адправіць інфармацыю вашага профілю трэцім асобам."</string>
     <string name="permlab_writeProfile" msgid="4679878325177177400">"увядзіце дадзеныя вашага профілю"</string>
-    <!-- outdated translation 6431297330378229453 -->     <string name="permdesc_writeProfile" product="default" msgid="4637366723793045603">"Дазваляе прыкладанням змяняць або дадаваць персанальныя дадзеныя профілю, якія захоўваюцца на вашай прыладзе (напрыклад, вашыя імя і кантактную інфармацыю). Гэта азначае, што іншыя прыкладанні могуць ідэнтыфікаваць вас і адправіць інфармацыю аб вашым профілі іншым асобам."</string>
+    <string name="permdesc_writeProfile" product="default" msgid="4637366723793045603">"Дазваляе прыкладанням змяняць ці дадаваць асабістую інфармацыю профіляў, захаваных на прыладзе, напрыклад ваша імя і кантактную інфармацыю. Такім чынам, іншыя прыкладанні могуць ідэнтыфікаваць вас і адпраўляць інфармацыю вашага профіля трэцім асобам."</string>
     <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"чытаць мой паток абнаўленняў"</string>
-    <!-- outdated translation 1300659548047580769 -->     <string name="permdesc_readSocialStream" product="default" msgid="3419050808547335320">"Дазваляе прыкладанням атрымліваць доступ да абнаўленняў вашых сяброў i сiнхранiзаваць гэтыя звесткi. З дапамогай шкоднасных прыкладанняў хтосьцi можа атрымаць доступ да вашай асабiстай перапiскi з сябрамi ў сацыяльных сетках."</string>
+    <string name="permdesc_readSocialStream" product="default" msgid="3419050808547335320">"Дазваляе прыкладанням атрымліваць доступ і сінхранізаваць абнаўленнi ад вас i вашых сяброў у сацыяльных сетках. З дапамогай шкоднасных прыкладанняў хтосьцi можа чытаць вашу асабiстую перапiску з сябрамі ў сацыяльных сетках."</string>
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"запісаць у мой паток абнаўленняў"</string>
-    <!-- outdated translation 8649864102944627446 -->     <string name="permdesc_writeSocialStream" product="default" msgid="3496277176955721451">"Дазваляе прыкладанням публiкаваць абнаўленнi вашых сяброў з сацыяльных сетак. З дапамогай шкоднасных прыкладанняў хтосьцi можа падрабляць абнаўленнi ад вашых сяброў i, напрыклад, збiраць вашы канфiдэнцыйныя звесткi."</string>
+    <string name="permdesc_writeSocialStream" product="default" msgid="3496277176955721451">"Дазваляе прыкладанням адлюстроўваць абнаўленнi ад вашых сяброў у сацыяльных сетках. З дапамогай шкоднасных прыкладанняў хтосьцi можа прыкінуцца вашым сябрам, каб выкрасцi паролi i iншыя канфiдэнцыйныя звесткi."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"чытаць падзеі календара, а таксама прыватную інфармацыю"</string>
-    <!-- outdated translation 5665520896961671949 -->     <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Дазваляе прыкладанням счытваць усе падзеі календара, захаваныя на планшэце, у тым ліку падзеі сяброў і калегаў. З дапамогай гэтага дазволу шкоднасныя прыкладанні могуць здабываць персанальную інфармацыю з гэтых календароў без ведама ўладальнікаў."</string>
-    <!-- outdated translation 5665520896961671949 -->     <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Дазваляе прыкладанням счытваць усе падзеі календара, захаваныя на планшэце, у тым ліку падзеі сяброў і калегаў. З дапамогай гэтага дазволу шкоднасныя прыкладанні могуць здабываць персанальную інфармацыю з гэтых календароў без ведама ўладальнікаў."</string>
+    <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Дазваляе прыкладанню счытваць усе мерапрыемствы календара, захаваныя на планшэце, у тым ліку мерапрыемствы сяброў і калег. Шкоднасныя прыкладанні могуць атрымліваць асабістую інфармацыю з гэтых календароў без ведама ўладальнікаў."</string>
+    <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Дазваляе прыкладанню счытваць усе мерапрыемствы календара, захаваныя на вашым тэлефоне, у тым ліку мерапрыемствы сяброў і калег. Шкоднасныя прыкладаннi могуць атрымліваць асабістую інфармацыю з гэтых календароў без ведама ўладальнікаў."</string>
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"дадаваць ці змяняць падзеі календара і адпраўляць электронную пошту да гасцей без ведама ўладальнікаў"</string>
-    <!-- outdated translation 5368129321997977226 -->     <string name="permdesc_writeCalendar" msgid="2243771395254848873">"Дазваляе прыкладанням адпраўляць запрашэнні на мерапрыемствы ад iмя ўладальніка календара і дадаваць, выдаляць, змяняць падзеі, якія можна змяняць на прыладзе, у тым ліку падзеі сяброў або калегаў. З дапамогай гэтага дазволу шкоднасныя прыкладанні могуць рассылаць спам , які выглядае як прыбыўшы ад уладальніка календара, змяняць падзеі без ведама ўладальнікаў або дадаваць падробленыя падзеі."</string>
+    <string name="permdesc_writeCalendar" msgid="2243771395254848873">"Дазваляе прыкладанням адпраўляць запрашэнні на мерапрыемствы ў якасці ўладальніка календара і дадаваць, выдаляць, рэдагаваць мерапрыемствы, якія можна змяняць на прыладзе, у тым ліку мерапрыемствы сяброў або калег. Шкоднасныя прыкладанні могуць адпраўляць паведамленні-спам, якія зыходзяць ад уладальніка календара, змяняць мерапрыемствы без ведама ўладальнікаў або дадаваць падробленыя мерапрыемствы."</string>
     <string name="permlab_accessMockLocation" msgid="8688334974036823330">"макет крыніц месцазнаходжання для тэставання"</string>
-    <!-- outdated translation 7648286063459727252 -->     <string name="permdesc_accessMockLocation" msgid="7577931556422993949">"Стварыць макет крыніц месцазнаходжанняў для тэставання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для змены месцазнаходжання і/або статусу, атрыманых з рэальных сістэм пазіцыявання, напрыклад з GPS або сеткі правайдэраў мабільнай сувязі."</string>
+    <string name="permdesc_accessMockLocation" msgid="7577931556422993949">"Дазваляе прыкладанням ствараць макет крыніц месцазнаходжання для тэставання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб змяняць месцазнаходжанне і/або статус, паведамляемы рэальнымі крыніцамі месцазнаходжання, напрыклад, GPS або правайдэрамі сеткі."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"доступ да дадатковых камандаў пастаўшчыка месцазнаходжання"</string>
-    <!-- outdated translation 1948144701382451721 -->     <string name="permdesc_accessLocationExtraCommands" msgid="6737736970602176133">"Доступ да дадатковых каманд пастаўшчыка месцазнаходжання. Шкоднасныя прыкладанні могуць карыстацца гэтым, каб умешвацца ў працу GPS і іншых крыніц месцазнаходжання."</string>
+    <string name="permdesc_accessLocationExtraCommands" msgid="6737736970602176133">"Дазваляе прыкладанням атрымліваць доступ да дадатковых каманд пастаўшчыка месца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб умешвацца ў працу GPS або іншых крыніц месцазнаходжання."</string>
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"дазвол на ўсталяванне пастаўшчыка месцазнаходжання"</string>
-    <!-- outdated translation 5449175116732002106 -->     <string name="permdesc_installLocationProvider" msgid="1742577679350078373">"Стварыць макет крыніц месца для тэставання. Шкоднае праграмнае забеспячэнне можа выкарыстаць гэта, каб змяніць месцазнаходжанне і/або статус, атрыманы з рэальных сістэм пазіцыянавання, напрыклад з GPS або сеткі правайдэраў мабільнай сувязі, або можа вызначаць ваша месцазнаходжанне і перадаваць звесткі на вонкавыя прылады."</string>
+    <string name="permdesc_installLocationProvider" msgid="1742577679350078373">"Стварае макет крыніц месцазнаходжання для тэставання. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта, каб змяняць месцазнаходжанне і/або статус, які перадаюць рэальныя крыніцы месцазнаходжання, напрыклад GPS або пастаўшчыкі паслуг сеткі, ці кантраляваць вашае месцазнаходжанне і перадаваць яго на знешнюю крыніцу."</string>
     <string name="permlab_accessFineLocation" msgid="8116127007541369477">"дакладнае (GPS) месцазнаходжанне"</string>
-    <!-- outdated translation 243973693233359681 -->     <string name="permdesc_accessFineLocation" product="tablet" msgid="5326423948268164934">"Доступ да дакладных крыніц месцаў (напрыклад, да глабальнай сістэмы пазіцыянавання на планшэце), калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб вызначыць, дзе вы знаходзіцеся, і могуць спажываць дадатковую магутнасць батарэі."</string>
-    <!-- outdated translation 243973693233359681 -->     <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Доступ да дакладных крыніц месцаў (напрыклад, да глабальнай сістэмы пазіцыянавання на планшэце), калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб вызначыць, дзе вы знаходзіцеся, і могуць спажываць дадатковую магутнасць батарэі."</string>
+    <string name="permdesc_accessFineLocation" product="tablet" msgid="5326423948268164934">"Дазволіць доступ да сістэм дакладнага пазіцыянавання на планшэце, напрыклад да GPS, там, дзе гэта магчыма. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта для вызначэння вашага месцазнаходжання, а таксама могуць дадаткова спажываць магутнасць акумулятару."</string>
+    <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Дазволіць доступ да сістэм дакладнага пазіцыянавання на тэлефоне, напрыклад да GPS, там, дзе гэта магчыма. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта для вызначэння вашага месцазнаходжання, а таксама могуць дадаткова спажываць магутнасць акумулятару."</string>
     <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"прыблізнае (заснаванае на дадзеных сеткі) месцазнаходжанне"</string>
-    <!-- outdated translation 3704633168985466045 -->     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="5460726396318105483">"Доступ да грубых крыніц месца (напрыклад, да базы дадзеных сотавай сеткі), каб вызначыць прыблізнае месцазнаходжанне планшэту, калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб прыкладна вызначыць, дзе вы знаходзіцеся."</string>
-    <!-- outdated translation 3704633168985466045 -->     <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"Доступ да грубых крыніц месца (напрыклад, да базы дадзеных сотавай сеткі), каб вызначыць прыблізнае месцазнаходжанне планшэту, калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб прыкладна вызначыць, дзе вы знаходзіцеся."</string>
+    <string name="permdesc_accessCoarseLocation" product="tablet" msgid="5460726396318105483">"Атрымаць доступ да прыблізных крыніц месцазнаходжання (напрыклад, да базы дадзеных сотавай сеткі), каб вызначыць прыблізнае месцазнаходжанне планшэта, калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб прыкладна вызначаць, дзе вы знаходзіцеся."</string>
+    <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"Каб вызначыць прыблізнае месцазнаходжанне тэлефона, атрымайце доступ да прыблізных крыніц месцазнаходжання (напрыклад, да базы дадзеных сотавай сеткі), калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб прыкладна вызначаць, дзе вы."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"доступ да SurfaceFlinger"</string>
-    <!-- outdated translation 6805241830020733025 -->     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дазваляе прыкладанням выкарыстоўваць нізкаўзроўневыя функцыі SurfaceFlinger."</string>
+    <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дазваляе прыкладанням выкарыстоўваць нізкаўзроўневыя функцыі SurfaceFlinger."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"чытаць буфер кадраў"</string>
-    <!-- outdated translation 7530020370469942528 -->     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дазваляе прыкладанню чытаць змесціва буфера кадраў."</string>
+    <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дазваляе прыкладанням счытваць змесціва буферу кадра."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"змяняць налады аудыё"</string>
-    <!-- outdated translation 5793461287365991922 -->     <string name="permdesc_modifyAudioSettings" msgid="7343951185408396919">"Дазваляе прыкладанням змяняць глабальныя налады аудыё, напрыклад гучнасць і маршрутызацыю."</string>
+    <string name="permdesc_modifyAudioSettings" msgid="7343951185408396919">"Дазваляе прыкладанням змяняць глабальныя налады аудыё, напрыклад гук і маршрутызацыю."</string>
     <string name="permlab_recordAudio" msgid="3876049771427466323">"запісваць аўдыё"</string>
-    <!-- outdated translation 6493228261176552356 -->     <string name="permdesc_recordAudio" msgid="2387462233976248635">"Дае прыкладанням доступ да шляха запісу аўдыё."</string>
+    <string name="permdesc_recordAudio" msgid="2387462233976248635">"Дазваляе прыкладанням атрымліваць доступ да шляху аудыёзапісу."</string>
     <string name="permlab_camera" msgid="3616391919559751192">"рабіць фатаграфіі і відэа"</string>
-    <!-- outdated translation 6004878235852154239 -->     <string name="permdesc_camera" msgid="1507407407002492176">"Дазваляе прыкладанням здымаць фатаграфіі і відэа з дапамогай камеры. Гэта дазваляе прыкладанням ў любы час збіраць выявы, якія бачыць камера."</string>
+    <string name="permdesc_camera" msgid="1507407407002492176">"Дазваляе прыкладанням рабiць фатаграфіі і відэа з камеры. Гэта дазваляе прыкладанням у любы час збіраць выявы, якія \"бачыць\" камера."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"цалкам адключыць планшэт"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"цалкам адключаць тэлефон"</string>
-    <!-- outdated translation 7379164636920817963 -->     <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Дазваляе прыкладанням цалкам адключаць планшэт. Гэта вельмі небяспечна."</string>
-    <!-- outdated translation 7379164636920817963 -->     <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Дазваляе прыкладанням цалкам адключаць планшэт. Гэта вельмі небяспечна."</string>
+    <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Дазваляе прыкладанням цалкам адключаць планшэт. Гэта вельмі небяспечна."</string>
+    <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Дазваляе прыкладанням цалкам адключаць тэлефон. Гэта вельмі небяспечна."</string>
     <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"прымусовая перазагрузка планшэта"</string>
     <string name="permlab_reboot" product="default" msgid="2898560872462638242">"прымусова перазагружаць тэлефон"</string>
-    <!-- outdated translation 4555793623560701557 -->     <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"Дазваляе прыкладанню прымусова перазагрузіць планшэт."</string>
-    <!-- outdated translation 4555793623560701557 -->     <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Дазваляе прыкладанню прымусова перазагрузіць планшэт."</string>
+    <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"Дазваляе прыкладанням прымусова перазагружаць планшэт."</string>
+    <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Дазваляе прыкладанням прымусова перазагружаць тэлефон."</string>
     <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"уключэнне і адключэнне файлавых сістэм"</string>
-    <!-- outdated translation 6253263792535859767 -->     <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"Дазваляе прыкладанням уключаць і адключаць файлавыя сістэмы для падлучэння зменных назапашвальнікаў."</string>
+    <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"Дазваляе прыкладанням падключаць і адключаць файлавыя сістэмы для здымных назапашвальнікаў."</string>
     <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"фарматаваць знешнія назапашвальнікі"</string>
-    <!-- outdated translation 574060044906047386 -->     <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"Дазваляе прыкладанням фарматаваць здымныя назапашвальнiкi."</string>
+    <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"Дазваляе прыкладанням фарматаваць здымны назапашвальнiк."</string>
     <string name="permlab_asec_access" msgid="3411338632002193846">"атрымаць інфармацыю аб унутранай памяці"</string>
-    <!-- outdated translation 8820326551687285439 -->     <string name="permdesc_asec_access" msgid="3094563844593878548">"Дазваляе прыкладанню атрымліваць інфармацыю аб унутранай памяці."</string>
+    <string name="permdesc_asec_access" msgid="3094563844593878548">"Дазваляе прыкладанню атрымліваць інфармацыю пра ўнутраную памяць."</string>
     <string name="permlab_asec_create" msgid="6414757234789336327">"стварыць унутраную памяць"</string>
-    <!-- outdated translation 2621346764995731250 -->     <string name="permdesc_asec_create" msgid="4558869273585856876">"Дазваляе прыкладанню ствараць унутраную памяць."</string>
+    <string name="permdesc_asec_create" msgid="4558869273585856876">"Дазваляе прыкладанням ствараць унутраную памяць."</string>
     <string name="permlab_asec_destroy" msgid="526928328301618022">"знішчыць унутраную памяць"</string>
-    <!-- outdated translation 2746706889208066256 -->     <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Дазваляе прыкладанню знішчаць унутраную памяць."</string>
-    <!-- outdated translation 2456287623689029744 -->     <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"падключыць/адключыць унутраную памяць"</string>
-    <!-- outdated translation 5934375590189368200 -->     <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Дазваляе прыкладанню падключаць/адключаць унутраную памяць."</string>
+    <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Дазваляе прыкладанням выдаляць унутраную памяць."</string>
+    <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"падключэнне/адключэнне ўнутранай памяці"</string>
+    <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Дазваляе прыкладанням падлучаць i адлучаць унутраную памяць."</string>
     <string name="permlab_asec_rename" msgid="7496633954080472417">"перайменаваць унутраную памяць"</string>
-    <!-- outdated translation 2152829985238876790 -->     <string name="permdesc_asec_rename" msgid="1794757588472127675">"Дазваляе праграмам змяняць імя ўнутранай памяці."</string>
+    <string name="permdesc_asec_rename" msgid="1794757588472127675">"Дазваляе прыкладанням змяняць імя ўнутранай памяці."</string>
     <string name="permlab_vibrate" msgid="7768356019980849603">"кіраваць вібрацыяй"</string>
-    <!-- outdated translation 2886677177257789187 -->     <string name="permdesc_vibrate" msgid="6284989245902300945">"Дазваляе прыкладанням кіраваць вібрацыяй."</string>
+    <string name="permdesc_vibrate" msgid="6284989245902300945">"Дазваляе прыкладанням кіраваць вібрацыяй."</string>
     <string name="permlab_flashlight" msgid="2155920810121984215">"кіраваць ўспышкай"</string>
-    <!-- outdated translation 6433045942283802309 -->     <string name="permdesc_flashlight" msgid="6522284794568368310">"Дазваляе прыкладанню кіраваць ліхтарыкам."</string>
+    <string name="permdesc_flashlight" msgid="6522284794568368310">"Дазваляе прыкладанню кіраваць ліхтарыкам."</string>
     <string name="permlab_manageUsb" msgid="1113453430645402723">"кіраваць спісам пажаданых і дазволеных USB-прылад"</string>
-    <!-- outdated translation 6148489202092166164 -->     <string name="permdesc_manageUsb" msgid="7776155430218239833">"Дазваляе выкарыстоўваць праграму для кіравання спісам пажаданых і дазволеных USB-прылад."</string>
+    <string name="permdesc_manageUsb" msgid="7776155430218239833">"Дазваляе прыкладанням кіраваць наладамі і дазволамі USB-прылад."</string>
     <string name="permlab_accessMtp" msgid="4953468676795917042">"рэалізаваць пратакол MTP"</string>
     <string name="permdesc_accessMtp" msgid="6532961200486791570">"Дазваляе атрымаць доступ да драйвер ядра MTP, каб рэалізаваць USB-пратакол MTP."</string>
     <string name="permlab_hardware_test" msgid="4148290860400659146">"тэставаць апаратнае забеспячэнне"</string>
-    <!-- outdated translation 3668894686500081699 -->     <string name="permdesc_hardware_test" msgid="6597964191208016605">"Дазваляе прыкладанням кіраваць рознымі перыферыйнымі прыладамі для тэставання абсталявання."</string>
+    <string name="permdesc_hardware_test" msgid="6597964191208016605">"Дазваляе прыкладанням кіраваць рознымі перыферыйнымі прыладамі для тэставання апаратнага абсталявання."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"непасрэдна набіраць тэлефонныя нумары"</string>
-    <!-- outdated translation 3369867353692722456 -->     <string name="permdesc_callPhone" msgid="6396463004110544744">"Дазваляе прыкладанням выклікаць тэлефонныя нумары без вашага ўмяшальніцтва. Шкодныя праграмы могуць рабіць непрадугледжаныя званкі за ваш кошт. Звярніце ўвагу: гэта не дазваляе прыкладанням выклікаць нумары экстраных службаў."</string>
+    <string name="permdesc_callPhone" msgid="6396463004110544744">"Дазваляе прыкладанням выклікаць тэлефонныя нумары без вашага ведама. Шкоднасныя прыкладанні могуць прывесці да з\'яўлення нечаканых выклікаў у вашым рахунку за паслугі тэлефоннай сувязі. Звярніце ўвагу, што гэты дазвол не дазваляе прыкладанню выклікаць экстраныя нумары."</string>
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"непасрэдна выклікаць любыя тэлефонныя нумары"</string>
-    <!-- outdated translation 244405067160028452 -->     <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Дазваляе прыкладанням тэлефанаваць на любы нумар, у тым лiку на нумары экстраных служб, без вашага ўмяшальніцтва. Шкодныя праграмы могуць рабіць непатрэбныя і незаконныя выклікі аварыйных службаў."</string>
+    <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Дазваляе прыкладанню тэлефанаваць на любы тэлефонны нумар, у тым лiку на экстраныя нумары, без вашага ведама. Шкоднасныя прыкладанні могуць рабіць непатрэбныя і незаконныя экстраныя выклікі."</string>
     <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"непасрэдна пачаць наладу CDMA-планшэта"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"непасрэдна запускаць налады тэлефона CDMA"</string>
-    <!-- outdated translation 6457447676108355905 -->     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Дазваляе прыкладанням запускаць падрыхтоўку CDMA. Шкоднасныя прыкладанні могуць без неабходнасці пачаць падрыхтоўку CDMA"</string>
+    <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Дазваляе прыкладанням запускаць рэзервы CDMA. Шкоднасныя прыкладанні могуць запускаць залішнія рэзервы CDMA."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"кіраваць абвесткамі абнаўлення месцазнаходжання"</string>
-    <!-- outdated translation 2300018303720930256 -->     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Дазваляе ўключаць/выключаць абнаўленнi апавяшчэнняў аб месцазнаходжанні праз радыё. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+    <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Дазваляе прыкладанням уключаць i адключаць апавяшчэннi аб абнаўленні месцазнаходжання ад радыё. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"атрымліваць доступ да ўласцівасцяў праверкі"</string>
-    <!-- outdated translation 7150307006141883832 -->     <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Дазваляе счытваць і запісваць уласцівасці, загружаныя службай рэгістрацыі. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+    <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Дазваляе прыкладанням сытваць/запісваць доступ да ўласцівасцяў, запампаваных службай праверкі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="permlab_bindGadget" msgid="776905339015863471">"выбіраць віджэты"</string>
-    <!-- outdated translation 2098697834497452046 -->     <string name="permdesc_bindGadget" msgid="8261326938599049290">"Дазваляе прыкладанням паведамляць сістэме, якія прыкладанні могуць выкарыстоўваць віджэты. З гэтым дазволам яны могуць даваць іншым прыкладанням доступ да персанальных дадзеных. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+    <string name="permdesc_bindGadget" msgid="8261326938599049290">"Дазваляе прыкладанням паведамляць сістэме, якая віджэты могуць быць выкарыстаны пэўнымі прыкладаннямі. Прыкладанне з гэтым дазволам можа прадастаўляць доступ да персанальных дадзеных іншым прыкладанням. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"змяняць стан тэлефона"</string>
-    <!-- outdated translation 3302284561346956587 -->     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дазваляе прыкладанням кіраваць тэлефоннымі функцыямі прылады. Прыкладанні з гэтым дазволам могуць пераключаць сеткі, уключаць і адключаць радыё на тэлефоне і г. д., нават не паведамляючы пра гэта."</string>
+    <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дазваляе прыкладанням кіраваць тэлефоннымі функцыямі прылады. Прыкладанне з гэтым дазволам можа пераключаць сеткі, уключаць і выключаць радыё на тэлефоне і г. д., нават не паведамляючы пра гэта."</string>
     <string name="permlab_readPhoneState" msgid="2326172951448691631">"чытаць стан тэлефона і ідэнтыфікацыйныя дадзеныя"</string>
-    <!-- outdated translation 188877305147626781 -->     <string name="permdesc_readPhoneState" msgid="5127767618743602782">"Дазваляе прыкладанням атрымліваць доступ да функцый тэлефона прылады. Прыкладанні з гэтым дазволам могуць вызначыць нумар тэлефона і серыйны нумар гэтага тэлефона, актыўнасць выкліка, нумар выкліканага абанента і таму падобнае."</string>
+    <string name="permdesc_readPhoneState" msgid="5127767618743602782">"Дазваляе прыкладанням атрымліваць доступ да тэлефонных функцый прылады. Прыкладанне з гэтым дазволам можа вызначаць нумар тэлефона і серыйны нумар гэтага тэлефона ці актыўны выклік, нумар выкліканага абанента і г. д."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"прадухіліць планшэт ад пераходу ў рэжым сну"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"забараняць тэлефону пераходзіць ў рэжым сну"</string>
-    <!-- outdated translation 4032181488045338551 -->     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дазваляе прыкладанню прадухіліць планшэт ад пераходу ў рэжым сну."</string>
-    <!-- outdated translation 4032181488045338551 -->     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дазваляе прыкладанню прадухіліць планшэт ад пераходу ў рэжым сну."</string>
+    <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дазваляе прыкладанням прадухіляць пераход планшэта ў рэжым сну."</string>
+    <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дазваляе прыкладанням прадухіляць тэлефон ад пераходу ў рэжым сну."</string>
     <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Уключыць або выключыць планшэт"</string>
     <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"уключаць або выключаць тэлефон"</string>
-    <!-- outdated translation 3853773100100451905 -->     <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дазваляе прыкладанням уключаць або выключаць планшэт"</string>
-    <!-- outdated translation 3853773100100451905 -->     <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Дазваляе прыкладанням уключаць або выключаць планшэт"</string>
+    <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дазваляе прыкладанням уключаць ці адключаць планшэт."</string>
+    <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Дазваляе прыкладанням уключаць або адключаць тэлефон."</string>
     <string name="permlab_factoryTest" msgid="3715225492696416187">"запусціць у рэжыме заводскага тэставання"</string>
     <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Запуск у якасці нізкаўзроўневага тэсты вытворцы, што дазваляе атрымаць поўны доступ да абсталявання планшэта. Даступна, толькі калі планшэт працуе ў рэжыме тэставання вытворцы."</string>
     <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Запусціць як нізкаўзроўневы тэст вытворцы, што дазваляе атрымаць поўны доступ да абсталявання тэлефона. Даступна, толькі калі прылада працуе ў рэжыме тэста вытворцы."</string>
     <string name="permlab_setWallpaper" msgid="6627192333373465143">"усталёўваць шпалеры"</string>
-    <!-- outdated translation 6417041752170585837 -->     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Дазваляе прыкладанням усталёўваць сiстэмныя шпалеры."</string>
+    <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Дазваляе прыкладанням ксталёўваць сiстэмныя шпалеры."</string>
     <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"усталёўваць падказкі памераў шпалер"</string>
-    <!-- outdated translation 6019479164008079626 -->     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Дазваляе прыкладанням задаваць падказкі па памеру сістэмных шпалераў."</string>
+    <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Дазваляе прыкладанням задаваць падказкі па памеры сістэмных шпалер."</string>
     <string name="permlab_masterClear" msgid="2315750423139697397">"скідаць сістэму да завадскіх наладаў"</string>
-    <!-- outdated translation 5033465107545174514 -->     <string name="permdesc_masterClear" msgid="3665380492633910226">"Дазваляе прыкладанням рабіць поўнае скіданне да завадскіх налад. Пры гэтым выдаляюцца ўсе дадзеныя, канфігурацыя і ўсталяваныя прыкладанні."</string>
+    <string name="permdesc_masterClear" msgid="3665380492633910226">"Дазваляе прыкладанню цалкам скідваць сістэму да заводскіх налад, выдаляючы ўсе дадзеныя, налады і ўсталяваныя прыкладанні."</string>
     <string name="permlab_setTime" msgid="2021614829591775646">"задаць час"</string>
-    <!-- outdated translation 209693136361006073 -->     <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Дазваляе прыкладанню змяняць час на планшэце."</string>
-    <!-- outdated translation 209693136361006073 -->     <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Дазваляе прыкладанню змяняць час на планшэце."</string>
+    <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Дазваляе прыкладанням змяняць час на гадзінніку планшэта."</string>
+    <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Дазваляе прыкладаннМ змяняць час на гадзінніку тэлефона."</string>
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"усталёўваць часавы пояс"</string>
-    <!-- outdated translation 2522877107613885139 -->     <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Дазваляе прыкладанню змяняць гадзінны пояс планшэта."</string>
-    <!-- outdated translation 2522877107613885139 -->     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Дазваляе прыкладанню змяняць гадзінны пояс планшэта."</string>
+    <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Дазваляе прыкладанням змяняць гадзінны пояс планшэта."</string>
+    <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Дазваляе прыкладанню змяняць гадзінны пояс тэлефона."</string>
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"выступаць у якасці службы AccountManagerService"</string>
-    <!-- outdated translation 6056903274106394752 -->     <string name="permdesc_accountManagerService" msgid="2684502137670299915">"Дазваляе прыкладанням тэлефанаваць на AccountAuthenticators"</string>
+    <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Дазваляе прыкладанням тэлефанаваць на AccountAuthenticators."</string>
     <string name="permlab_getAccounts" msgid="4549918644233460103">"выяўляць вядомыя ўліковыя запісы"</string>
-    <!-- outdated translation 857622793935544694 -->     <string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Дазваляе прыкладанням атрымліваць спіс уліковых запісаў, якія ёсць на планшэце."</string>
-    <!-- outdated translation 857622793935544694 -->     <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Дазваляе прыкладанням атрымліваць спіс уліковых запісаў, якія ёсць на планшэце."</string>
+    <string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Дазваляе прыкладанню атрымліваць спіс уліковых запісаў, вядомых планшэту."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Дазваляе прыкладанню атрымліваць спіс уліковых запісаў, вядомых тэлефону."</string>
     <string name="permlab_authenticateAccounts" msgid="3940505577982882450">"выступаць у якасці аўтэнтыфікатара ўліковага запісу"</string>
-    <!-- outdated translation 4006839406474208874 -->     <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Дазваляе прыкладанню выкарыстоўваць магчымасці сродку праверкі сапраўднасці ўліковых запісаў AccountManager, у тым ліку ствараць уліковыя запісы, атрымліваць і наладжваць паролі для іх."</string>
+    <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Дазваляе прыкладанням выкарыстоўваць магчымасці сродку праверкі сапраўднасці ўліковых запісаў AccountManager, у тым ліку ствараць уліковыя запісы, атрымліваць і наладжваць паролі для іх."</string>
     <string name="permlab_manageAccounts" msgid="4440380488312204365">"кіраванне спісам уліковых запісаў"</string>
-    <!-- outdated translation 8804114016661104517 -->     <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Дазваляе прыкладанням выконваць такія аперацыі, як дадаванне і выдаленне ўліковых запісаў альбо выдаленне іх пароляў."</string>
+    <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Дазваляе прыкладанням выконваць даданне і выдаленне ўліковых запісаў або выдаленне іх пароляў."</string>
     <string name="permlab_useCredentials" msgid="6401886092818819856">"выкарыстоўваць уліковыя дадзеныя ўліковага запісу"</string>
-    <!-- outdated translation 7416570544619546974 -->     <string name="permdesc_useCredentials" msgid="7984227147403346422">"Дазваляе прыкладанню запытваць ключы аўтэнтыфікацыі."</string>
+    <string name="permdesc_useCredentials" msgid="7984227147403346422">"Дазваляе прыкладанням запытваць ключы аўтэнтыфікаціі."</string>
     <string name="permlab_accessNetworkState" msgid="6865575199464405769">"праглядаць стан сеткі"</string>
-    <!-- outdated translation 558721128707712766 -->     <string name="permdesc_accessNetworkState" msgid="479772796952547198">"Дазваляе прыкладанням праглядаць стан усіх сетак."</string>
+    <string name="permdesc_accessNetworkState" msgid="479772796952547198">"Дазваляе прыкладанню праглядаць стан усіх сетак."</string>
     <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"поўны доступ да інтэрнэту"</string>
-    <!-- outdated translation 4593339106921772192 -->     <string name="permdesc_createNetworkSockets" msgid="5963922297444265950">"Дазваляе прыкладанням ствараць сеткавыя злучальнікі."</string>
+    <string name="permdesc_createNetworkSockets" msgid="5963922297444265950">"Дазваляе прыкладанню ствараць сеткавыя сокеты."</string>
     <string name="permlab_writeApnSettings" msgid="505660159675751896">"змяняць/перахопліваць сеткавыя налады і трафік"</string>
-    <!-- outdated translation 2369786339323021771 -->     <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Дазваляе прыкладанням змяняць налады сеткі, перахапляць і правяраць увесь сеткавы трафік, напрыклад для змены проксі і порта любога APN. Шкоднасныя прыкладанні могуць адсочваць, перанакіроўваць або змяняць сеткавыя пакеты без вашага ведама."</string>
+    <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Дазваляе прыкладанням змяняць налады сеткі, перахапляць і правяраць увесь сеткавы трафік, напрыклад для змены проксі-сервера і порта любога APN. Шкоднасныя прыкладанні могуць адсочваць, перанакіроўваць або змяняць сеткавыя пакеты без вашага ведама."</string>
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"змяніць падлучэнне да сеткі"</string>
-    <!-- outdated translation 4199958910396387075 -->     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Дазваляе прыкладанням змяняць стан сеткавага падключэння."</string>
-    <!-- outdated translation 2702121155761140799 -->     <string name="permlab_changeTetherState" msgid="5952584964373017960">"Змяняць падлучэнне да мадэму"</string>
-    <!-- outdated translation 8905815579146349568 -->     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Дазваляе прыкладанню змяняць стан прывязанага сеткавага падключэння."</string>
+    <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Дазваляе прыкладанням змяняць стан сеткавага падключэння."</string>
+    <string name="permlab_changeTetherState" msgid="5952584964373017960">"змяніць прывязку да падлучэння"</string>
+    <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Дазваляе прыкладанням змяняць стан прывязкі да сеткі."</string>
     <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"змяняць налады выкарыстання фонавых дадзеных"</string>
-    <!-- outdated translation 1001482853266638864 -->     <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Дазваляе прыкладанням мяняць налады фонавай перадачы дадзеных."</string>
+    <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Дазваляе прыкладанням змяняць налады выкарыстання зыходных дадзеных."</string>
     <string name="permlab_accessWifiState" msgid="8100926650211034400">"праглядаць стан Wi-Fi"</string>
-    <!-- outdated translation 485796529139236346 -->     <string name="permdesc_accessWifiState" msgid="7770452658226256831">"Дазваляе прыкладанням праглядаць інфармацыю аб стане Wi-Fi."</string>
+    <string name="permdesc_accessWifiState" msgid="7770452658226256831">"Дазваляе прыкладанням праглядаць інфармацыю аб стане Wi-Fi."</string>
     <string name="permlab_changeWifiState" msgid="7280632711057112137">"змяняць стан Wi-Fi"</string>
-    <!-- outdated translation 2950383153656873267 -->     <string name="permdesc_changeWifiState" msgid="7399961004537946240">"Дазваляе прыкладанням падключацца да кропак доступу Wi-Fi і адключацца ад іх, а таксама ўносіць змены ў наладжаныя сеткі Wi-Fi."</string>
+    <string name="permdesc_changeWifiState" msgid="7399961004537946240">"Дазваляе прыкладанням падлучацца і адключацца ад кропак доступу Wi-Fi і ўносіць змяненні ў наладжаныя сеткі Wi-Fi."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"дазваляе прыём Wi-Fi Multicast"</string>
-    <!-- outdated translation 8199464507656067553 -->     <string name="permdesc_changeWifiMulticastState" msgid="7633598524564320817">"Дазваляе прыкладанням атрымліваць пакеты, не напраўленыя непасрэдна на прыладу. Гэта можа быць карысна пры выяўленні блізкіх паслуг. Гэта выкарыстоўвае больш магутнасцяў, чым рэжым нешматадрасных перадач."</string>
-    <!-- outdated translation 1092209628459341292 -->     <string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"кіраванне bluetooth"</string>
-    <!-- outdated translation 3511795757324345837 -->     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Дазваляе прыкладанню наладжваць лакальны планшэт Bluetooth, а таксама вызначаць і падключацца да выдаленых прылад."</string>
-    <!-- outdated translation 3511795757324345837 -->     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Дазваляе прыкладанню наладжваць лакальны планшэт Bluetooth, а таксама вызначаць і падключацца да выдаленых прылад."</string>
+    <string name="permdesc_changeWifiMulticastState" msgid="7633598524564320817">"Дазваляе прыкладаннямм атрымліваць пакеты, якія не былі адрасаваня непасрэдна вашай прыладзе. Гэта можа быць карысна пры выяўленні службаў, даступных побач. У гэтым рэжыме выкарыстоўваецца больш энергіі, чым у рэжыме аднаадраснай перадачы."</string>
+    <string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"адмiнiстраванне Bluetooth"</string>
+    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Дазваляе прыкладанням наладжваць лакальны планшэт Bluetooth, выяўляць і падлучаць выдаленыя прылады."</string>
+    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Дазваляе прыкладанням наладжваць лакальны тэлефон Bluetooth, а таксама знаходзіць выдаленыя прылады i падлучацца да ix."</string>
+    <string name="permlab_accessWimaxState" msgid="1232061307208861588">"Прагляд стану WiMAX"</string>
+    <string name="permdesc_accessWimaxState" msgid="5914958077555177749">"Дазваляе прыкладанням праглядаць інфармацыю пра стан WiMAX."</string>
+    <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Змяніць стан WiMAX"</string>
+    <string name="permdesc_changeWimaxState" msgid="3328853825006455912">"Дазваляе прыкладанням падключацца і адключацца ад сеткі WiMAX."</string>
     <string name="permlab_bluetooth" msgid="8361038707857018732">"ствараць злучэнні Bluetooth"</string>
-    <!-- outdated translation 4191941825910543803 -->     <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Дазваляе прыкладанню праглядаць канфігурацыю лакальнага планшэта Bluetooth, а таксама ствараць і прымаць падключэнні да спалучаных прылад."</string>
-    <!-- outdated translation 4191941825910543803 -->     <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Дазваляе прыкладанню праглядаць канфігурацыю лакальнага планшэта Bluetooth, а таксама ствараць і прымаць падключэнні да спалучаных прылад."</string>
+    <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Дазваляе прыкладанню праглядаць канфігурацыю лакальнага планшэту Bluetooth, а таксама здзяйсняць і прымаць злучэнні са спалучанымі прыладамі."</string>
+    <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Дазваляе прыкладанню праглядаць канфігурацыю лакальнага тэлефона Bluetooth, а таксама здзяйсняць і прымаць злучэнні са спалучанымі прыладамі."</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"кантроль Near Field Communication"</string>
-    <!-- outdated translation 9171401851954407226 -->     <string name="permdesc_nfc" msgid="7120611819401789907">"Дазваляе прыкладанню звязвацца з тэгамі, карткамі і чытачамі Near Field Communication (NFC)."</string>
+    <string name="permdesc_nfc" msgid="7120611819401789907">"Дазваляе прыкладаннzv спалучацца з тэгамі, картамі і счытваючымі прыладамі Near Field Communication (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="4977406164311535092">"адключаць блакаванне клавіятуры"</string>
-    <!-- outdated translation 3189763479326302017 -->     <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Дазваляе прыкладанням адключаць блакіроўку клавіятуры і абарону паролем. Добры прыклад гэтага — адключэнне блакіроўкі тэлефона пры атрыманні ўваходнага выкліка тэлефона, паўторнае ўключэнне блакіроўкі клавіятуры, калі выклік завершаны."</string>
+    <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Дазваляе прыкладанням адключаць блакаванне клавіятуры і любыя сродкі абароны, звязаныя з паролем. Прыкладам гэтага з\'яўляецца адключэнне тэлефонам блакавання клавіятуры пры атрыманні ўваходнага выкліку і паўторнае ўключэнне блакавання клавіятуры, калі выклік завершаны."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"чытаць параметры сінхранізацыі"</string>
-    <!-- outdated translation 5315925706353341823 -->     <string name="permdesc_readSyncSettings" msgid="5464056785274229278">"Дазваляе прыкладанням счытваць налады сінхранізацыі (напрыклад, ці ўключана сінхранізацыя для кантактаў)."</string>
+    <string name="permdesc_readSyncSettings" msgid="5464056785274229278">"Дазваляе прыкладанням змяняць налады сінхранізацыі, напрыклад, ці будзе сінхранізацыя ўключана для прыкладання People."</string>
     <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"запісваць параметры сінхранізацыі"</string>
-    <!-- outdated translation 2498201614431360044 -->     <string name="permdesc_writeSyncSettings" msgid="1466056564502117130">"Дазваляе прыкладанням мяняць налады сінхранізацыі, напрыклад дазвол сінхранізацыі для Кантактаў."</string>
+    <string name="permdesc_writeSyncSettings" msgid="1466056564502117130">"Дазваляе прыкладанню змяняць налады сінхранізацыі, напрыклад, ці будзе сінхранізацыя ўключана для прыкладання People."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"чытаць статыстыку сінхранізацыі"</string>
-    <!-- outdated translation 7511448343374465000 -->     <string name="permdesc_readSyncStats" msgid="3801971839939951678">"Дазваляе прыкладанням счытваць статыстыку сінхранізацыі, напрыклад гісторыю здзейсненых сінхранізацый."</string>
+    <string name="permdesc_readSyncStats" msgid="3801971839939951678">"Дазваляе прыкладанню счытваць статыстыку сінхранізацыі, напрыклад гісторыю здзейсненых сінхранізацый."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"чытаць падпісаныя каналы"</string>
-    <!-- outdated translation 3622200625634207660 -->     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Дазваляе прыкладанням атрымліваць інфармацыю аб сінхранізацыі бягучых каналаў."</string>
+    <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Дазваляе прыкладанням атрымліваць інфармацыю пра каналы, якія сінхранізуюцца ў бягучы момант."</string>
     <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"запісваць каналы, на якія ёсць падпіска"</string>
-    <!-- outdated translation 8121607099326533878 -->     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Дазваляе прыкладанням змяняць бягучыя сінхранізуемыя каналы. Гэта можа дазволіць шкоднасным прыкладанням змяняць сінхранізаваныя каналы."</string>
-    <!-- outdated translation 432535716804748781 -->     <string name="permlab_readDictionary" msgid="8410247960433376352">"чытаць карыстальніцкі слоўнік"</string>
-    <!-- outdated translation 1082972603576360690 -->     <string name="permdesc_readDictionary" msgid="8977815988329283705">"Дазваляе прыкладанням счытваць любыя прыватныя словы, імёны і фразы, якія карыстальнік можа захоўваць у карыстальніцкім слоўніку."</string>
-    <!-- outdated translation 6703109511836343341 -->     <string name="permlab_writeDictionary" msgid="2296383164914812772">"пісаць у карыстальніцкі слоўнік"</string>
-    <!-- outdated translation 2241256206524082880 -->     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Дазваляе прыкладанням запісваць новыя словы ў слоўнік карыстальніка."</string>
+    <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Дазваляе прыкладанням змяняць бягучыя каналы сінхранізавання. Шкоднасныя прыкладанні могуць змяняць вашы каналы сінхранізацыi."</string>
+    <string name="permlab_readDictionary" msgid="8410247960433376352">"чытаць карыстальніцкі слоўнік"</string>
+    <string name="permdesc_readDictionary" msgid="8977815988329283705">"Дазваляе прыкладанню счытваць любыя прыватныя словы, імёны і фразы, якія карыстальнік можа захоўваць у карыстальніцкім слоўніку."</string>
+    <string name="permlab_writeDictionary" msgid="2296383164914812772">"запісаць у карыстальніцкі слоўнік"</string>
+    <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Дазваляе прыкладанням запісваць новыя словы ў карыстальніцкі слоўнік."</string>
     <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"змяніць/выдаліць змесціва USB-назапашвальнiка"</string>
     <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"змяняць/выдаляць змесціва SD-карты"</string>
-    <!-- outdated translation 6594393334785738252 -->     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Дазваляе прыкладанню запісваць дадзеныя на USB-назапашвальнiк."</string>
-    <!-- outdated translation 6594393334785738252 -->     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дазваляе прыкладанню запісваць дадзеныя на USB-назапашвальнiк."</string>
+    <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Дазваляе прыкладаням выконваць запіс ва USB-назапашвальнік."</string>
+    <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дазваляе прыкладанням запісваць на SD-карту."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"змяніць/выдаліць унутраныя носьбіты змесціва"</string>
-    <!-- outdated translation 8232008512478316233 -->     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дазваляе прыкладанням змяняць змесціва ўнутранага сховішча інфармацыі."</string>
+    <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дазваляе прыкладанням змяняць змесціва ўнутранай памяці."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"доступ да файлавай сістэмы кэша"</string>
-    <!-- outdated translation 1624734528435659906 -->     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дазваляе прыкладанням чытаць і запісваць дадзеныя ў файлавую сістэму кэша."</string>
+    <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дазваляе прыкладанню счытваць і выконваць запіс у файлавую сістэму кэш-памяці."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"рабіць/прымаць iнтэрнэт-выклікі"</string>
-    <!-- outdated translation 6320376185606661843 -->     <string name="permdesc_use_sip" msgid="4717632000062674294">"Дазваляе прыкладанню выкарыстоўваць службу SIP, каб рабіць/прымаць iнтэрнэт-выклікі."</string>
+    <string name="permdesc_use_sip" msgid="4717632000062674294">"Дазваляе прыкладанням выкарыстоўваць службу SIP, каб прымаць/рабіць Інтэрнэт-выклікі."</string>
     <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"чытаць дадзеныя выкарыстання сеткі"</string>
-    <!-- outdated translation 6040738474779135653 -->     <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Дазваляе прыкладанням чытаць дадзеныя дзённiка выкарыстання для пэўных сетак і прыкладанняў."</string>
+    <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Дазваляе прыкладанню счытваць дадзеныя аб гісторыі выкарыстання сеткі для пэўных сетак і прыкладанняў."</string>
     <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"кіраванне палітыкай сеткі"</string>
-    <!-- outdated translation 3723795285132803958 -->     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладанням кіраваць сеткавымі палітыкамі і вызначаць правілы для прыкладанняў."</string>
+    <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладаннм кіраваць сеткавымі палітыкамі і вызначаць правілы пэўных прыкладанняў."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змяніць улік выкарыстання сеткі"</string>
-    <!-- outdated translation 8702285686629184404 -->     <string name="permdesc_modifyNetworkAccounting" msgid="8553240749784321765">"Дазваляе мадыфікаваць улік выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+    <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
-    <string name="policydesc_limitPassword" msgid="9083400080861728056">"Кіраванне даўжынёй і колькасцю знакаў на экране разблакоўкі пароляў"</string>
+    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
-    <!-- outdated translation 933601759466308092 -->     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Сачыць за колькасцю няправільных спроб уводу пароляў пры разблакоўцы экрана і блакаваць планшэт або сціраць ўсе дадзеныя на планшэце, калі ўводзіцца занадта шмат няправільных пароляў"</string>
-    <!-- outdated translation 933601759466308092 -->     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Сачыць за колькасцю няправільных спроб уводу пароляў пры разблакоўцы экрана і блакаваць планшэт або сціраць ўсе дадзеныя на планшэце, калі ўводзіцца занадта шмат няправільных пароляў"</string>
+    <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Сачыць за колькасцю няправільных набраных пароляў падчас разблакоўкі экрана і блакаваць планшэт або сціраць усе дадзеныя на ім, калі няправільны пароль набраны занадта шмат разоў."</string>
+    <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Сачыць за колькасцю няправільных набраных пароляў падчас разблакоўкі экрана і блакаваць тяэлефон або сціраць усе дадзеныя на ім, калі набрана занадта шмат няправільных пароляў."</string>
     <string name="policylab_resetPassword" msgid="2620077191242688955">"Змяненне паролю разблакоўкі экрана"</string>
-    <string name="policydesc_resetPassword" msgid="5391240616981297361">"Змяненне паролю разблакоўкі экрана"</string>
+    <string name="policydesc_resetPassword" msgid="605963962301904458">"Змяніць пароль разблакоўкі экрана."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Заблакаваць экран"</string>
-    <string name="policydesc_forceLock" msgid="5696964126226028442">"Кіраванне часам і спосабам блакоўкі экрана"</string>
+    <string name="policydesc_forceLock" msgid="1141797588403827138">"Кіраванне часам і спосабам блакавання экрана"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Сцерці ўсе дадзеныя"</string>
-    <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Сцерці дадзеныя планшэта без папярэджання, выканаўшы скід налад дадзеных"</string>
-    <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Сцерці дадзеныя тэлефона без папярэджання, выканаўшы скід налад дадзеных"</string>
+    <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Выдаліць дадзеныя з планшэта без папярэджання, выканаўшы скід налад."</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Выдаліць дадзеныя з тэлефона без папярэджання, выканаўшы скід налад."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Усталяваць глабальны проксі прылады"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Усталяваць глабальны проксі-cервер прылады, які будзе выкарыстоўвацца, калі палітыка актыўная. Толькі першы адміністратар прылады ўсталёўвае эфектыўныя глабальныя проксі-серверы."</string>
     <string name="policylab_expirePassword" msgid="885279151847254056">"Нал. тэрм. дз. пар. блак. экр."</string>
-    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Кантраляваць, як часта трэба мяняць пароль для блакавання экрана"</string>
+    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Кіраваць частатой змены паролю для блакавання экрана."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Усталяваць шыфраванне сховішча."</string>
-    <!-- outdated translation 2504984732631479399 -->     <string name="policydesc_encryptedStorage" msgid="8877192718681120469">"Патрабаваць шыфраванне захаваных дадзеных прыкладання"</string>
+    <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Запыт на шыфраванне захаваных дадзеных прыкладанняў."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Адключыць камеры"</string>
-    <string name="policydesc_disableCamera" msgid="5680054212889413366">"Забарона выкарыстання ўсіх камер прылады"</string>
+    <string name="policydesc_disableCamera" msgid="2306349042834754597">"Забараніць выкарыстанне ўсіх камер прылады."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Галоўная старонка"</item>
     <item msgid="869923650527136615">"Мабільны"</item>
@@ -635,14 +646,14 @@
     <string name="sipAddressTypeHome" msgid="6093598181069359295">"Галоўная старонка"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"Працоўны"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"Іншае"</string>
-    <!-- outdated translation 3731488827218876115 -->     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Увядзіце PIN-код"</string>
-    <!-- outdated translation 5965173481572346878 -->     <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Увядзіце PUK і новы PIN-код"</string>
+    <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Увядзіце PIN-код"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Увядзіце PUK-код і новы PIN-код"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK"</string>
-    <!-- outdated translation 2987350144349051286 -->     <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Новы PIN-код"</string>
-    <!-- outdated translation 7906561917570259833 -->     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Дакраніцеся, каб увесці пароль"</font></string>
-    <!-- outdated translation 9138158344813213754 -->     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Увядзіце пароль для разблакавання"</string>
-    <!-- outdated translation 638347075625491514 -->     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Увядзіце PIN-код для разблакоўкі"</string>
-    <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Няправільны PIN-код"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Новы PIN-код"</string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Дакраніцеся, каб увесці пароль"</font></string>
+    <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Увядзіце пароль для разблакавання"</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Каб разблакаваць, увядзіце PIN-код"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Няправільны PIN-код."</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"Каб разблакаваць, націсніце \"Меню\", затым 0."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Нумар экстранай службы"</string>
     <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Не абслугоўваецца"</string>
@@ -653,8 +664,9 @@
     <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Экстраны выклік"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Вярнуцца да выкліку"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Правільна!"</string>
-    <!-- outdated translation 4817583279053112312 -->     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Паспрабуйце яшчэ раз"</string>
-    <!-- outdated translation 6237443657358168819 -->     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Паспрабуйце яшчэ раз"</string>
+    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Паспрабуйце яшчэ раз"</string>
+    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Паўтарыце спробу"</string>
+    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Перавышана максімальная колькасць спроб разблакоўкі праз Фэйскантроль"</string>
     <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Зарадка, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_charged" msgid="4938930459620989972">"Зараджаны."</string>
     <string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
@@ -662,9 +674,9 @@
     <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Няма SIM-карты."</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Няма SIM-карты ў планшэце."</string>
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"У тэлефоне няма SIM-карты."</string>
-    <!-- outdated translation 8874620818937719067 -->     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Устаўце SIM-карту."</string>
-    <!-- outdated translation 7138450788301444298 -->     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string>
-    <!-- outdated translation 1631853574702335453 -->     <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Вашая SIM-картка поўнасцю адключаная."\n"Звярніцеся да пастаўшчыка паслуг мабільнай сувязі, каб атрымаць іншую SIM-карту."</string>
+    <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Усталюйце SIM-карту."</string>
+    <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ваша SIM-карта была адключана назаўсёды."\n" Звяжыцеся з аператарам бесправадной сувязі, каб атрымаць іншую SIM-карту."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Кнопка папярэдняй кампазiцыi"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Кнопка наступнай кампазiцыi"</string>
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Кнопка паўзы"</string>
@@ -673,19 +685,14 @@
     <string name="emergency_calls_only" msgid="6733978304386365407">"Толькі экстраныя выклікі"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Сетка заблакаваная"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-карта заблакавана PUK-кодам."</string>
-    <!-- outdated translation 635967534992394321 -->     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Глядзіце Інструкцыю карыстальніка або звяжыцеся са службай падтрымкі."</string>
+    <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Глядзіце \"Інструкцыю для карыстальніка\" або звяжыцеся са службай тэхнiчнай падтрымкі."</string>
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-карта заблакаваная."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Разблакаванне SIM-карты..."</string>
-    <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6481623830344107222) -->
-    <skip />
-    <!-- no translation found for lockscreen_too_many_failed_password_attempts_dialog_message (2725973286239344555) -->
-    <skip />
-    <!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6216672706545696955) -->
-    <skip />
-    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (9191611984625460820) -->
-    <skip />
-    <!-- no translation found for lockscreen_failed_attempts_almost_glogin (2590227559763762751) -->
-    <skip />
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Вы няправільна ўвялі пароль пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Вы няправільна ўвялі PIN-код пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакаваць планшэт з дапамогай уваходу ў Google."\n\n" Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакаваць тэлефон з дапамогай уваходу ў Google."\n\n" Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спробаў (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спробаў (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да заводскіх налад."</string>
@@ -693,14 +700,14 @@
     <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Паўтарыце спробу праз <xliff:g id="NUMBER">%d</xliff:g> с."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Забылі ўзор?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Разблакаванне ўліковага запісу"</string>
-    <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Занадта шмат спробаў узору!"</string>
-    <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Каб разблакаваць, увайдзіце праз уліковы запіс Google"</string>
+    <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Занадта шмат спроб паўтарыць шаблон!"</string>
+    <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Каб разблакаваць, увайдзіце ў свой уліковы запіс Google."</string>
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Імя карыстальніка (электронная пошта)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Пароль"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Увайсці"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Няправільнае імя карыстальніка ці пароль."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="8253152905532900548">"Забыліся на імя карыстальніка або пароль?"\n"Наведайце"<b>"google.com/accounts/recovery"</b></string>
-    <string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Праверка..."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Забыліся на імя карыстальніка або пароль?"\n"Наведайце "<b>"google.com/accounts/recovery"</b></string>
+    <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Праверка..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Разблакаваць"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Гук уключаны"</string>
     <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Гук выключаны"</string>
@@ -717,14 +724,13 @@
     <string name="factorytest_not_system" msgid="4435201656767276723">"Дзеянне FACTORY_TEST падтрымліваецца толькі для пакетаў, усталяваных на шляху /system/app."</string>
     <string name="factorytest_no_action" msgid="872991874799998561">"Пакет, які выконвае дзеянне FACTORY_TEST, не знойдзены."</string>
     <string name="factorytest_reboot" msgid="6320168203050791643">"Перазагрузіць"</string>
-    <string name="js_dialog_title" msgid="8143918455087008109">"Старонка з адрасам \"<xliff:g id="TITLE">%s</xliff:g>\" кажа:"</string>
+    <string name="js_dialog_title" msgid="1987483977834603872">"На старонцы з адрасам <xliff:g id="TITLE">%s</xliff:g> вызначана:"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <!-- no translation found for js_dialog_before_unload (730366588032430474) -->
-    <skip />
+    <string name="js_dialog_before_unload" msgid="730366588032430474">"Пакiнуць гэту старонку?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Націсніце \"OK\", каб працягнуць, або \"Адмена\", каб застацца на бягучай старонцы."</string>
     <string name="save_password_label" msgid="6860261758665825069">"Пацвердзіць"</string>
-    <!-- outdated translation 1068216937244567247 -->     <string name="double_tap_toast" msgid="2729045387923870404">"Падказка: націсніце двойчы, каб павялічыць або паменшыць."</string>
-    <string name="autofill_this_form" msgid="1272247532604569872">"Аўтазапаўненне"</string>
-    <string name="setup_autofill" msgid="8154593408885654044">"Усталёўка аўтазапаўнення"</string>
+    <string name="double_tap_toast" msgid="4595046515400268881">"Падказка: двойчы націсніце, каб павялічыць або паменшыць."</string>
+    <string name="autofill_this_form" msgid="4616758841157816676">"Аўтазапаўненне"</string>
+    <string name="setup_autofill" msgid="7103495070180590814">"Усталяванне аўтазапаўнення"</string>
     <string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
     <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
     <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -742,25 +748,27 @@
     <string name="autofill_area" msgid="3547409050889952423">"Плошча"</string>
     <string name="autofill_emirate" msgid="2893880978835698818">"Эмірат"</string>
     <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"чытаць гісторыю браўзэра і закладак"</string>
-    <!-- outdated translation 4981489815467617191 -->     <string name="permdesc_readHistoryBookmarks" msgid="4577476392604595921">"Дазваляе прыкладанням счытваць усе URL, якія наведвалiся з браўзэра, а таксама ўсе закладкi."</string>
+    <string name="permdesc_readHistoryBookmarks" msgid="4577476392604595921">"Дазваляе прыкладанням счытваць усе URL, якія наведвалiся з браўзэра, а таксама ўсе закладкi браўзэра."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"пісаць гісторыю браўзэра і закладак"</string>
-    <!-- outdated translation 7193514090469945307 -->     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="1757103804824209530">"Дазваляе прыкладанням змяняць гісторыю браўзэра або закладкі, якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэтую магчымасць, каб выдаляць або змяняць дадзеныя вашага браўзэра."</string>
-    <!-- outdated translation 7193514090469945307 -->     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"Дазваляе прыкладанням змяняць гісторыю браўзэра або закладкі, якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэтую магчымасць, каб выдаляць або змяняць дадзеныя вашага браўзэра."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="1757103804824209530">"Дазваляе прыкладанням змяняць гісторыю браўзэра або закладкі, якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэту магчымасць для выдалення або змены дадзеных вашага браўзэра."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"Дазваляе прыкладанням змяняць гісторыю браўзэра або закладак, захаваных у тэлефоне. Шкоднасныя прыкладанні могуць выкарыстоўваць гэту магчымасць для выдалення або змены дадзеных вашага браўзэра."</string>
     <string name="permlab_setAlarm" msgid="5924401328803615165">"Усталяваць сігнал у будзільніку"</string>
-    <!-- outdated translation 5966966598149875082 -->     <string name="permdesc_setAlarm" msgid="316392039157473848">"Дазваляе прыкладанням задаваць сігнал усталяванага прыкладання будзільніка. Пэўныя прыкладанні будзільніка не могуць рэалізаваць гэтую функцыю."</string>
+    <string name="permdesc_setAlarm" msgid="316392039157473848">"Дазваляе прыкладанню ўсталёўваць сігнал на ўсталяваным прыкладанні будзільніка. Пэўныя прыкладанні будзільніка не могуць рэалізоўваць гэтую магчымасць."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"дадаць галасавое паведамленне"</string>
-    <!-- outdated translation 4828507394878206682 -->     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Дазваляе праграме дадаваць паведамленні ў паштовую скрыню галасавых паведамленняў."</string>
-    <!-- outdated translation 4715212655598275532 -->     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Змяніць дазволы геапазіцыянавання для браўзэра"</string>
-    <!-- outdated translation 4011908282980861679 -->     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Дазваляе прыкладанням змяняць дазволы геалакацыі браўзэра. Шкодныя прыкладанні могуць карыстацца гэтым, каб дазваляць адпраўку інфармацыі аб месцазнаходжанні адвольным вэб-сайтам."</string>
+    <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Дазваляе прыкладанням дадаваць паведамленні ў вашу скрыню галасавой пошты."</string>
+    <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"змяніць дазволы геапазіцыянавання для браўзэра"</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Дазваляе прыкладанням змяняць дазволы геалакацыі браўзэра. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дазваляць адпраўку інфармацыі аб месцазнаходжанні выпадковым вэб-сайтам."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"верыфікаваць пакеты"</string>
-    <!-- outdated translation 6033195477325381106 -->     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дазваляе прыкладанням правяраць магчымасць усталёўкі пакету."</string>
+    <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дазваляе прыкладанням правяраць магчымасць усталявання пакету."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"прывязаць да верыфікатару пакету"</string>
-    <!-- outdated translation 2409521927385789318 -->     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дазваляе ўладальніку рабіць запыты верыфікатараў пакету. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дазваляе ўладальніку рабіць запыты верыфікатараў пакету. Не патрабуецца для звычайных прыкладанняў."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"атрымаць доступ да паслядоўных партоў"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Дазваляе ўладальніку атрымліваць доступ да паслядоўных партоў з дапамогай API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Вы хочаце, каб браўзэр запомніў гэты пароль?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не цяпер"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запомніць"</string>
     <string name="save_password_never" msgid="8274330296785855105">"Ніколі"</string>
-    <!-- outdated translation 5661861460947222274 -->     <string name="open_permission_deny" msgid="7374036708316629800">"У вас няма дазволу адкрываць гэтую старонку."</string>
+    <string name="open_permission_deny" msgid="7374036708316629800">"У вас няма дазволу на адкрыццё гэтай старонкі."</string>
     <string name="text_copied" msgid="4985729524670131385">"Тэкст скапіяваны ў буфер абмену."</string>
     <string name="more_item_label" msgid="4650918923083320495">"Больш"</string>
     <string name="prepend_shortcut_label" msgid="2572214461676015642">"Меню+"</string>
@@ -859,9 +867,9 @@
     <string name="weeks" msgid="6509623834583944518">"тыд."</string>
     <string name="year" msgid="4001118221013892076">"год"</string>
     <string name="years" msgid="6881577717993213522">"г."</string>
-    <!-- outdated translation 3359437293118172396 -->     <string name="VideoView_error_title" msgid="5927895235831021723">"Немагчыма прайграць відэа"</string>
-    <!-- outdated translation 897920883624437033 -->     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Гэтае відэа не падыходзіць для патокавай перадачы на ​​гэтую прыладу."</string>
-    <!-- outdated translation 710301040038083944 -->     <string name="VideoView_error_text_unknown" msgid="4309847331399592194">"На жаль, гэтае відэа не можа быць прайграна."</string>
+    <string name="VideoView_error_title" msgid="3534509135438353077">"Праблема з відэа"</string>
+    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Відэа не падыходзіць для патокавай перадачы на ​​гэту прыладу."</string>
+    <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Немагчыма прайграць гэта відэа."</string>
     <string name="VideoView_error_button" msgid="2822238215100679592">"ОК"</string>
     <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="noon" msgid="7245353528818587908">"апоўдні"</string>
@@ -877,7 +885,7 @@
     <string name="replace" msgid="5781686059063148930">"Замяніць..."</string>
     <string name="delete" msgid="6098684844021697789">"Выдаліць"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Скапіяваць URL"</string>
-    <!-- outdated translation 6738556348861347240 -->     <string name="selectTextMode" msgid="1018691815143165326">"Вылучыць тэкст..."</string>
+    <string name="selectTextMode" msgid="1018691815143165326">"Выбраць тэкст"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Вылучэнне тэксту"</string>
     <string name="addToDictionary" msgid="9090375111134433012">"дадаць у слоўнік"</string>
     <string name="deleteText" msgid="7070985395199629156">"выдаліць"</string>
@@ -891,57 +899,52 @@
     <string name="yes" msgid="5362982303337969312">"ОК"</string>
     <string name="no" msgid="5141531044935541497">"Адмяніць"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
-    <!-- outdated translation 1760724998928255250 -->     <string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
+    <string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
     <string name="capital_on" msgid="1544682755514494298">"Уключыць"</string>
     <string name="capital_off" msgid="6815870386972805832">"Адключана"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Завяршыць дзеянне з дапамогай"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Выкарыстоўваць па змаўчанні для гэтага дзеяння."</string>
-    <!-- outdated translation 4815455344600932173 -->     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ачысціць налады па змаўчанні ў меню \"Налады &gt; Прыкладанні &gt; Кіраванне прыкладаннямі."</string>
-    <string name="chooseActivity" msgid="1009246475582238425">"Выберыце дзеянне."</string>
-    <!-- outdated translation 7892597146032121735 -->     <string name="chooseUsbActivity" msgid="6894748416073583509">"Выберыце праграму для USB-прылады"</string>
-    <!-- outdated translation 1691104391758345586 -->     <string name="noApplications" msgid="2991814273936504689">"Ніякае прыкладанне не можа выканаць гэтае дзеянне."</string>
+    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ачысціць па змаўчанні ў раздзеле \"Налады сістэмы &gt; Прыкладанні &gt; Спампаваныя\"."</string>
+    <string name="chooseActivity" msgid="7486876147751803333">"Выберыце дзеянне"</string>
+    <string name="chooseUsbActivity" msgid="6894748416073583509">"Выберыце прыкладанне для USB-прылады"</string>
+    <string name="noApplications" msgid="2991814273936504689">"Няма прыкладанняў, якія могуць выконваць гэты працэс."</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <string name="aerr_application" msgid="932628488013092776">"На жаль, прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> спынілася."</string>
     <string name="aerr_process" msgid="4507058997035697579">"На жаль, працэс <xliff:g id="PROCESS">%1$s</xliff:g> спыніўся."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <!-- no translation found for anr_activity_application (1904477189057199066) -->
-    <skip />
-    <!-- no translation found for anr_activity_process (5776209883299089767) -->
-    <skip />
-    <!-- no translation found for anr_application_process (8941757607340481057) -->
-    <skip />
-    <!-- no translation found for anr_process (6513209874880517125) -->
-    <skip />
+    <string name="anr_activity_application" msgid="1904477189057199066">"Прыкладанне <xliff:g id="APPLICATION">%2$s</xliff:g> не адказвае."\n\n"Закрыць яго?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"Працэс <xliff:g id="ACTIVITY">%1$s</xliff:g> не адказвае."\n\n"Закрыць яго?"</string>
+    <string name="anr_application_process" msgid="8941757607340481057">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> не адказвае. Закрыць яго?"</string>
+    <string name="anr_process" msgid="6513209874880517125">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> не адказвае."\n\n"Закрыць яго?"</string>
     <string name="force_close" msgid="8346072094521265605">"ОК"</string>
     <string name="report" msgid="4060218260984795706">"Справаздача"</string>
     <string name="wait" msgid="7147118217226317732">"Чакаць"</string>
-    <!-- outdated translation 8323761616052121936 -->     <string name="launch_warning_title" msgid="1547997780506713581">"Прыкладанне перанакіраванае"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Старонка не адказвае на запыты."\n\n"Закрыць яе?"</string>
+    <string name="launch_warning_title" msgid="1547997780506713581">"Прыкл. перанакіраванае"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> зараз запушчанае."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> запушчанае."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Шкала"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Заўсёды паказваць"</string>
-    <!-- outdated translation 2953716574198046484 -->     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Каб зноў уключыць, перайдзіце ў Налады &gt; Прыкладанні &gt; Кіраванне прыкладаннямі."</string>
-    <!-- no translation found for smv_application (3307209192155442829) -->
-    <skip />
+    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Зноў уключыце гэта ў раздзеле \"Сістэмныя налады &gt; Прыкладанні &gt; Спампаваныя\"."</string>
+    <string name="smv_application" msgid="3307209192155442829">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> (працэс <xliff:g id="PROCESS">%2$s</xliff:g>) парушыла ўласную палітыку StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> парушыў уласную палітыку StrictMode."</string>
-    <!-- outdated translation 378740715658358071 -->     <string name="android_upgrading_title" msgid="1584192285441405746">"Абнаўленне Android..."</string>
-    <!-- no translation found for android_upgrading_apk (7904042682111526169) -->
-    <skip />
-    <!-- outdated translation 7959542881906488763 -->     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск прыкладанняў."</string>
+    <string name="android_upgrading_title" msgid="1584192285441405746">"Абнаўленне Android..."</string>
+    <string name="android_upgrading_apk" msgid="7904042682111526169">"Аптымізацыя прыкладання <xliff:g id="NUMBER_0">%1$d</xliff:g> з <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск прыкладанняў."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Завяршэнне загрузкі."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Прыкладанне \"<xliff:g id="APP">%1$s</xliff:g>\" запушчанае"</string>
-    <!-- outdated translation 2423977499339403402 -->     <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Выберыце, каб пераключыцца да прыкладання"</string>
-    <!-- outdated translation 1135403633766694316 -->     <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Пераключыць прыкладанні?"</string>
-    <!-- outdated translation 4592075610079319667 -->     <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ужо запушчана іншае прыкладанне, якое павінна быць спыненае перад запускам новага."</string>
+    <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Націсніце, каб перайсці да прыкладання"</string>
+    <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Пераключыць прыкладанні?"</string>
+    <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ужо запушчана іншае прыкладанне, якое павінна быць спынена перад запускам новага."</string>
     <string name="old_app_action" msgid="493129172238566282">"Вярнуцца да <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
-    <!-- outdated translation 942967900237208466 -->     <string name="old_app_description" msgid="2082094275580358049">"Не запускайце новае прыкладанне."</string>
+    <string name="old_app_description" msgid="2082094275580358049">"Не запускайце новыя прыкладанні."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Запусціць <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
-    <!-- outdated translation 6830398339826789493 -->     <string name="new_app_description" msgid="1932143598371537340">"Спыніць старое прыкладанне, не захоўваючы яго."</string>
-    <string name="sendText" msgid="5132506121645618310">"Выберыце дзеянне для тэксту"</string>
+    <string name="new_app_description" msgid="1932143598371537340">"Спыніць старыя прыкладанні без захавання."</string>
+    <string name="sendText" msgid="5209874571959469142">"Выберыце дзеянне для тэкста"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Гучнасць званка"</string>
     <string name="volume_music" msgid="5421651157138628171">"Гучнасць прайгравальніка"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Прайграваецца праз Bluetooth"</string>
-    <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Выбрана ціхая мелодыя"</string>
+    <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Усталяваны ціхі рэжым"</string>
     <string name="volume_call" msgid="3941680041282788711">"Гучнасць падчас размовы"</string>
     <string name="volume_bluetooth_call" msgid="2002891926351151534">"Гучнасць Bluetooth падчас выкліку"</string>
     <string name="volume_alarm" msgid="1985191616042689100">"Гучнасць будзільніка"</string>
@@ -965,30 +968,35 @@
     <item quantity="one" msgid="1634101450343277345">"Адкрытая сетка Wi-Fi даступная"</item>
     <item quantity="other" msgid="7915895323644292768">"Даступны адкрытыя сеткі Wi-Fi"</item>
   </plurals>
-    <string name="wifi_available_sign_in" msgid="9157196203958866662">"Уваход у сетку Wi-Fi"</string>
+    <string name="wifi_available_sign_in" msgid="4029489716605255386">"Увайдзіце ў сетку Wi-Fi"</string>
     <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" дрэннае падключэнне да Інтэрнэту."</string>
+    <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" дрэннае падключэнне да Інтэрнэту."</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2804722042556269129">"Пачаць работу Wi-Fi Direct. Гэта адключыць Wi-Fi кліента/кропку доступу."</string>
-    <string name="wifi_p2p_failed_message" msgid="1820097493844848281">"Немагчыма запусціць Wi-Fi Direct"</string>
-    <string name="wifi_p2p_pbc_go_negotiation_request_message" msgid="3170321684621420428">"Запыт злучэння Wi-Fi Direct ад <xliff:g id="P2P_DEVICE_ADDRESS">%1$s</xliff:g>. Націсніце \"ОК\", каб прыняць."</string>
-    <string name="wifi_p2p_pin_go_negotiation_request_message" msgid="5177412094633377308">"Запыт злучэння Wi-Fi Direct ад <xliff:g id="P2P_DEVICE_ADDRESS">%1$s</xliff:g>. Увядзіце PIN-код для працягу."</string>
-    <string name="wifi_p2p_pin_display_message" msgid="2834049169114922902">"Для працягу настройкі злучэння неабходна ўвесці PIN-код WPS <xliff:g id="P2P_WPS_PIN">%1$s</xliff:g> на аднарангавай прыладзе <xliff:g id="P2P_CLIENT_ADDRESS">%2$s</xliff:g>"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Пачаць работу Wi-Fi Direct. Гэта адключыць кліента або кропку доступу Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Немагчыма запусціць Wi-Fi Direct."</string>
+    <string name="accept" msgid="1645267259272829559">"Прыняць"</string>
+    <string name="decline" msgid="2112225451706137894">"Адхіліць"</string>
+    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрашэнне адпраўлена"</string>
+    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Запрашэнне далучыцца"</string>
+    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Ад:"</string>
+    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Каму:"</string>
+    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Увядзіце патрэбны PIN-код:"</string>
+    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код"</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Дакраніцеся, каб наладзіць"</string>
     <string name="select_character" msgid="3365550120617701745">"Уставіць сімвал"</string>
-    <!-- outdated translation 7630529934366549163 -->     <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невядомае прыкладанне"</string>
+    <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невядомае прыкладанне"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string>
-    <!-- outdated translation 1289331457999236205 -->     <string name="sms_control_message" msgid="4073755190243093924">"Адпраўляецца вялікая колькасць SMS. Выберыце \"OK\", каб працягнуць, ці \"Адмена\", каб спыніць адпраўку."</string>
+    <string name="sms_control_message" msgid="4073755190243093924">"Адпраўляецца вялікая колькасць SMS-паведамленняў. Націсніце \"OK\", каб працягнуць, ці \"Адмена\", каб спыніць адпраўку."</string>
     <string name="sms_control_yes" msgid="2532062172402615953">"ОК"</string>
     <string name="sms_control_no" msgid="1715320703137199869">"Адмяніць"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM-карта выдаленая"</string>
     <string name="sim_removed_message" msgid="2333164559970958645">"Мабільная сетка будзе недаступная да перазагрузкі з дзеючай SIM-картай."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Гатова"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"SIM-карта дадазеная"</string>
-    <string name="sim_added_message" msgid="1209265974048554242">"Для доступу да мабільнай сеткі неабходна перазагрузіць прыладу."</string>
+    <string name="sim_added_message" msgid="6599945301141050216">"Перазагрузіце прыладу, каб атрымаць доступ да мабільнай сеткі."</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"Перазапусціць"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"Усталяваць час"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"Усталяваць дату"</string>
@@ -997,40 +1005,40 @@
     <string name="no_permissions" msgid="7283357728219338112">"Дазволу не патрабуецца"</string>
     <string name="perms_hide" msgid="7283915391320676226"><b>"Не паказваць"</b></string>
     <string name="perms_show_all" msgid="2671791163933091180"><b>"Паказаць усе"</b></string>
-    <string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-назапашвальнік"</string>
+    <string name="usb_storage_activity_title" msgid="4465055157209648641">"Унiверсальны USB-назапашвальнік"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"USB падлучаны"</string>
-    <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Вы падключыліся да кампутара праз USB. Націсніце кнопку ніжэй, калі вы хочаце капіраваць файлы з кампутара і USB-назапашвальнiка Android."</string>
-    <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Вы падключыліся да кампутара праз USB. Націсніце кнопку ніжэй, калі хочаце капіяваць файлы з кампутара і вашай SD-карты Android."</string>
+    <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Вы падлучаны да камп\'ютара праз USB. Націсніце на кнопку ніжэй, калі жадаеце капіраваць файлы з камп\'ютара на USB-назапашвальнік прылады Android і наадварот."</string>
+    <string name="usb_storage_message" product="default" msgid="805351000446037811">"Вы падключыліся да камп\'ютара праз USB. Націсніце на кнопку ніжэй, калі вы жадаеце скапіраваць файлы з камп\'ютара на SD-карту прылады Android і наадварот."</string>
     <string name="usb_storage_button_mount" msgid="1052259930369508235">"Уключыць USB-назапашвальнiк"</string>
-    <string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Праблема з выкарыстаннем USB-назапашвальнiка для прылады захоўвання дадзеных USB."</string>
-    <string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Праблема з выкарыстаннем SD-карты для USB-назапашвальнiка дадзеных."</string>
+    <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"Паўстала праблема з выкарыстаннем USB-назапашвальнiка ва ўнiверсальным USB-назапашвальнiку."</string>
+    <string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"Паўстала праблема выкарыстання SD-карты ва ўнiверсальным USB-назапашвальнiку."</string>
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB падключаны"</string>
-    <string name="usb_storage_notification_message" msgid="7380082404288219341">"Выберыце файлы для капіявання паміж тэлефонам і кампутарам."</string>
+    <string name="usb_storage_notification_message" msgid="939822783828183763">"Дакраніцеся, каб капіяваць файлы з камп\'ютара цi на яго."</string>
     <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Выключыць USB-назапашвальнiк"</string>
-    <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Выберыце, каб адключыць гэты USB-назапашвальнiк."</string>
+    <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"Націсніце, каб адключыць USB-назапашвальнік."</string>
     <string name="usb_storage_stop_title" msgid="660129851708775853">"USB-назапашвальнік выкарыстоўваецца"</string>
-    <string name="usb_storage_stop_message" product="nosdcard" msgid="1368842269463745067">"Перш чым адключыць USB-назпашвальнiк, пераканайцеся, што вы адключылі (...выцягнулі...) USB-назапашвальнiк Android з кампутара."</string>
-    <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Перш чым адключыць USB-назапашвальнік, пераканайцеся, што SD-карта Android адключана ад кампутара."</string>
+    <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"Перш чым адключыць USB-назапашвальнік, адключыце(\"вымiце\") USB-назапашвальнік прылады Android ад камп\'ютара."</string>
+    <string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"Перш чым адключыць USB-назапашвальнік, адключыце(\"вымiце\") SD-карту вашай прылады Android з камп\'ютара."</string>
     <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Адключыць USB-назапашвальнiк"</string>
-    <string name="usb_storage_stop_error_message" msgid="143881914840412108">"Праблема адключэння USB-назапашвальнiка. Пераканайцеся ў тым, што вы адлучылі хост USB, а затым паўтарыце спробу."</string>
+    <string name="usb_storage_stop_error_message" msgid="1970374898263063836">"Памылка адключэння USB-назапашвальніка. Пераканайцеся, што вы адключылі хост USB, а потым паўтарыце спробу."</string>
     <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Падключыць USB-назапашвальнiк"</string>
-    <!-- outdated translation 3202838234780505886 -->     <string name="dlg_confirm_kill_storage_users_text" msgid="6206212680430268343">"Калі вы падлучыце USB-назапашвальнік, некаторыя прыкладанні, якія вы выкарыстоўваеце, спыняцца і могуць быць недаступныя, пакуль USB-назапашвальнік не будзе адключаны."</string>
+    <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Калі вы ўключыце USB-назапашвальнік, некаторыя прыкладанні, якія вы выкарыстоўваеце, спыняцца і могуць быць недаступныя, пакуль USB-назапашвальнік не будзе адключаны."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"Памылка працы USB"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Падлучана як медыя-прылада"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Падключаны як камера"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Падлучаны як усталявальнік"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Падключаны да USB-прылады"</string>
-    <string name="usb_notification_message" msgid="4447869605109736382">"Націсніце, каб убачыць параметры USB"</string>
-    <!-- outdated translation 7980995592595097841 -->     <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Фарматаваць USB-назапашвальнiк"</string>
-    <!-- outdated translation 7980995592595097841 -->     <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Фарматаваць USB-назапашвальнiк"</string>
-    <!-- outdated translation 8296908079722897772 -->     <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Фарматаваць USB-назапашвальнiк, выдаліўшы ўсе файлы, якія захоўваюцца там? Адмянiць нельга"</string>
-    <!-- outdated translation 8296908079722897772 -->     <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Фарматаваць USB-назапашвальнiк, выдаліўшы ўсе файлы, якія захоўваюцца там? Адмянiць нельга"</string>
+    <string name="usb_notification_message" msgid="2290859399983720271">"Націсніце, каб убачыць іншыя параметры USB."</string>
+    <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Фарматаваць USB-назапашвальнiк?"</string>
+    <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Фарматаваць SD-карту?"</string>
+    <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Усе файлы, якія захоўваюцца на вашым USB-назапашвальніку, будуць выдалены. Гэта дзеянне не можа быць адменена."</string>
+    <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Усе дадзеныя на карце будуць страчаны."</string>
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"Фармат"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Прылада адладкі USB падключана"</string>
-    <!-- outdated translation 8592219392855947984 -->     <string name="adb_active_notification_message" msgid="1016654627626476142">"Гэты кіёск абсталяваны Nexus S."</string>
-    <!-- outdated translation 6865512749462072765 -->     <string name="select_input_method" msgid="4653387336791222978">"Выберыце метад уводу"</string>
-    <!-- outdated translation 6324843080254191535 -->     <string name="configure_input_methods" msgid="9091652157722495116">"Налада метадаў уводу"</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"Націсніце, каб адключыць адладку USB."</string>
+    <string name="select_input_method" msgid="4653387336791222978">"Выберыце метад уводу"</string>
+    <string name="configure_input_methods" msgid="9091652157722495116">"Наладзіць метады ўводу"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
@@ -1039,12 +1047,12 @@
     <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Праверка на наяўнасць памылак."</string>
     <string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"Пусты USB-назапашвальнiк"</string>
     <string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"Пустая SD-карта"</string>
-    <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"USB-назапашвальнiк пусты або файлавая сістэма не падтрымліваецца."</string>
-    <string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"SD-карта пустая, або файлавая сістэма не падтрымліваецца."</string>
+    <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="7840121067427269500">"USB-назапашвальнік пусты або мае файлавую сістэму, якая не падтрымліваецца."</string>
+    <string name="ext_media_nofs_notification_message" product="default" msgid="8641065641786923604">"SD-карта пустая або мае файлавую сістэму, якая не падтрымліваецца."</string>
     <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Пашкоджаны USB-назапашвальнiк"</string>
     <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"SD-карта пашкоджаная"</string>
-    <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB-назапашвальнiк пашкоджаны. Магчыма, вам прыйдзецца яго перафарматаваць."</string>
-    <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"SD-карта пашкоджаная. Магчыма, вам прыйдзецца перафарматаваць яе."</string>
+    <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="1795917578395333280">"USB-назапашвальнік пашкоджаны. Паспрабуйце адфарматаваць яго."</string>
+    <string name="ext_media_unmountable_notification_message" product="default" msgid="1753898567525568253">"SD-карта пашкоджана. Паспрабуйце адфарматаваць яе."</string>
     <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-назапашвальнiк нечакана быў выдалены"</string>
     <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"SD-карта была нечакана выдалена"</string>
     <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Адключыце USB-назапашвальнiк, перш чым выцягваць яго, каб пазбегнуць страты дадзеных."</string>
@@ -1057,13 +1065,13 @@
     <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"SD-карта выдаленая"</string>
     <string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"USB-назапашвальнiк выдалены. Уставіць новыя носьбіты."</string>
     <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD-карта выдаленая. Устаўце новую."</string>
-    <string name="activity_list_empty" msgid="4168820609403385789">"Няма адпаведных дзеянняў"</string>
+    <string name="activity_list_empty" msgid="1675388330786841066">"Адпаведныя дзеянні не знойдзены."</string>
     <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"абнавіць статыстыку выкарыстання кампанентаў"</string>
-    <!-- outdated translation 891553695716752835 -->     <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Дазваляе мяняць сабраную статыстыку выкарыстання кампанента. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
-    <!-- outdated translation 1660908117394854464 -->     <string name="permlab_copyProtectedData" msgid="4341036311211406692">"Дазваляе выклікаць службы кантэйнера па змаўчанні для капіявання змесціва. Не выкарыстоўваецца звычайнымi прыкладаннямi."</string>
-    <!-- outdated translation 537780957633976401 -->     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Дазваляе выклікаць службы кантэйнера па змаўчанні для капіявання змесціва. Не выкарыстоўваецца звычайнымi прыкладаннямi."</string>
-    <!-- outdated translation 1311810005957319690 -->     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Націсніце двойчы, каб кіраваць маштабаваннем"</string>
-    <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Памылка ўключэння віджэту"</string>
+    <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Дазваляе прыкладанням змяняць сабраную статыстыку выкарыстання кампанентаў. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+    <string name="permlab_copyProtectedData" msgid="4341036311211406692">"капіяваць змесціва"</string>
+    <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Дазваляе прыкладанням выклікаць службу захавання па змаўчанні для капіявання змесціва. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+    <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двойчы дакраніцеся, каб змянiць маштаб"</string>
+    <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Немагчыма дадаць віджэт."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Пачаць"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Пошук"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"Адправіць"</string>
@@ -1073,37 +1081,37 @@
     <string name="ime_action_default" msgid="2840921885558045721">"Выканаць"</string>
     <string name="dial_number_using" msgid="5789176425167573586">"Набраць нумар"\n"з выкарыстаннем <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="create_contact_using" msgid="4947405226788104538">"Стварыць кантакт"\n"з дапамогай<xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <!-- outdated translation 6824538733852821001 -->     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Гэтыя адно або некалькі прыкладанняў пытаюцца дазволу на доступ да вашага ўліковага запісу цяпер і ў будучыні."</string>
+    <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Гэтыя адно або некалькі прыкладанняў запытваюць дазвол на доступ да вашага ўліковага запісу цяпер і ў будучыні."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Дазволіць гэты запыт?"</string>
-    <string name="grant_permissions_header_text" msgid="2722567482180797717">"Запыт на доступ"</string>
+    <string name="grant_permissions_header_text" msgid="6874497408201826708">"Запыт на доступ"</string>
     <string name="allow" msgid="7225948811296386551">"Дазволіць"</string>
     <string name="deny" msgid="2081879885755434506">"Забараніць"</string>
-    <string name="permission_request_notification_title" msgid="5390555465778213840">"Запытаны дазвол"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Запытаны дазвол"\n"для ўліковага запісу<xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_title" msgid="6486759795926237907">"Дазвол запытаны"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Запытаны дазвол"\n"для ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Метад уводу"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Сінхранізацыя"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Спецыяльныя магчымасці"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Шпалеры"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Змена шпалер"</string>
-    <string name="vpn_title" msgid="8219003246858087489">"VPN актываваны."</string>
+    <string name="vpn_title" msgid="19615213552042827">"VPN актываваны"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN актывуецца прыкладаннем <xliff:g id="APP">%s</xliff:g>"</string>
-    <string name="vpn_text" msgid="1610714069627824309">"Націсніце, каб кіраваць сеткай."</string>
-    <string name="vpn_text_long" msgid="4907843483284977618">"Падлучаны да <xliff:g id="SESSION">%s</xliff:g>. Націсніце, каб кiраваць сеткай."</string>
+    <string name="vpn_text" msgid="3011306607126450322">"Дакраніцеся, каб кіраваць сеткай."</string>
+    <string name="vpn_text_long" msgid="6407351006249174473">"Падлучаны да сеанса \"<xliff:g id="SESSION">%s</xliff:g>\". Дакраніцеся, каб кiраваць сеткай."</string>
     <string name="upload_file" msgid="2897957172366730416">"Выберыце файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Файл не выбраны"</string>
     <string name="reset" msgid="2448168080964209908">"Скінуць"</string>
     <string name="submit" msgid="1602335572089911941">"Перадаць"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Рэжым \"У машыне\" ўключаны"</string>
-    <string name="car_mode_disable_notification_message" msgid="668663626721675614">"Выберыце, каб выйсці з рэжыму \"Ў аўтамабілі\"."</string>
+    <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Дакраніцеся, каб выйсці з рэжыму \"Штурман\"."</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"USB-мадэм або кропка доступу Wi-Fi актыўныя"</string>
-    <string name="tethered_notification_message" msgid="3067108323903048927">"Націсніце, каб змяніць налады"</string>
+    <string name="tethered_notification_message" msgid="6857031760103062982">"Націсніце, каб наладзіць."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Назад"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Далей"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Прапусціць"</string>
     <string name="throttle_warning_notification_title" msgid="4890894267454867276">"Інтэнсіўнае выкарыстанне перадачы дадзеных праз мабільную сетку"</string>
-    <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Націсніце, каб даведацца больш аб выкарыстанні перадачы дадзеных праз мабільную сетку"</string>
+    <string name="throttle_warning_notification_message" msgid="3340822228599337743">"Націсніце, каб атрымаць дадатковыя звесткі аб выкарыстанні мабiльнай перадачы дадзеных."</string>
     <string name="throttled_notification_title" msgid="6269541897729781332">"Ліміт мабільнай перадачы дадзеных перавышаны"</string>
-    <string name="throttled_notification_message" msgid="4712369856601275146">"Націсніце, каб даведацца больш аб выкарыстанні перадачы дадзеных праз мабільную сетку"</string>
+    <string name="throttled_notification_message" msgid="5443457321354907181">"Націсніце, каб атрымаць дадатковыя звесткі аб выкарыстанні мабiльнай перадачы дадзеных."</string>
     <string name="no_matches" msgid="8129421908915840737">"Няма супадзенняў"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Знайсці на старонцы"</string>
   <plurals name="matches_found">
@@ -1111,10 +1119,10 @@
     <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> з <xliff:g id="TOTAL">%d</xliff:g>"</item>
   </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Гатова"</string>
-    <string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"Адключэнне USB-назапашвальнiка..."</string>
-    <string name="progress_unmounting" product="default" msgid="5556813978958789471">"Адключэнне SD-карты..."</string>
-    <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Ачышчэнне USB-назапашвальнiка..."</string>
-    <string name="progress_erasing" product="default" msgid="2115214724367534095">"Ачышчэнне SD-карты..."</string>
+    <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Адключэнне USB-назапашвальнiка..."</string>
+    <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Адключэнне SD-карты..."</string>
+    <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Выдаленне дадзеных з USB-назапашвальнiка..."</string>
+    <string name="progress_erasing" product="default" msgid="6596988875507043042">"Выдаленне дадзеных з SD-карты..."</string>
     <string name="format_error" product="nosdcard" msgid="6299769563624776948">"Немагчыма ачысцiць USB-назапашвальнік."</string>
     <string name="format_error" product="default" msgid="7315248696644510935">"Немагчыма ачысцiць SD-карту."</string>
     <string name="media_bad_removal" msgid="7960864061016603281">"SD-карта была вынутая да адключэння"</string>
@@ -1133,17 +1141,17 @@
     <string name="gpsVerifYes" msgid="2346566072867213563">"Так"</string>
     <string name="gpsVerifNo" msgid="1146564937346454865">"Не"</string>
     <string name="sync_too_many_deletes" msgid="5296321850662746890">"Выдаліць перавышаны ліміт"</string>
-    <string name="sync_too_many_deletes_desc" msgid="7030265992955132593">"Ёсць выдаленыя элементы (<xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>) для тыпу сiнхранiзацыi <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, уліковы запіс <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Што вы хочаце зрабіць?"</string>
-    <string name="sync_really_delete" msgid="8933566316059338692">"Выдаліць элементы."</string>
-    <string name="sync_undo_deletes" msgid="8610996708225006328">"Скасаваць выдаленне."</string>
-    <string name="sync_do_nothing" msgid="8717589462945226869">"Нічога зараз не рабіць."</string>
-    <!-- outdated translation 4191313562041125787 -->     <string name="choose_account_label" msgid="5655203089746423927">"Выберыце ўліковы запіс"</string>
+    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Выдалена элементаў для тыпу сінхранiзацыi \"<xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>\": <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>. Уліковы запіс <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Што вы жадаеце зрабіць?"</string>
+    <string name="sync_really_delete" msgid="2572600103122596243">"Выдаліць элементы."</string>
+    <string name="sync_undo_deletes" msgid="2941317360600338602">"Скасаваць выдаленні"</string>
+    <string name="sync_do_nothing" msgid="3743764740430821845">"Нічога зараз не рабіць"</string>
+    <string name="choose_account_label" msgid="5655203089746423927">"Выберыце ўліковы запіс"</string>
     <string name="add_account_label" msgid="2935267344849993553">"Дадаць уліковы запіс"</string>
-    <string name="choose_account_text" msgid="6891230675141555481">"Які ўліковы запіс вы хацелі б выкарыстоўваць?"</string>
+    <string name="choose_account_text" msgid="6303348737197849675">"Які ўліковы запіс вы жадаеце выкарыстоўваць?"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"Дадаць уліковы запіс"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Інкрэмент"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Дэкрэмент"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="1343063395404990189">"Націсніце і ўтрымлівайце кнопку <xliff:g id="VALUE">%s</xliff:g>."</string>
+    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Націсніце і ўтрымлівайце <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Перасуньце палец уверх, каб павялiчыць адрэзак, або ўніз, каб паменшыць."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"На хвiлiну больш"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"На хвiлiну менш"</string>
@@ -1172,10 +1180,10 @@
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Змена рэжыму"</string>
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
-    <!-- outdated translation 4540794444768613567 -->     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Выберыце прыкладанне"</string>
+    <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Выберыце прыкладанне"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Апублікаваць з дапамогай"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Адправiць з дапамогай прыкладання <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
-    <!-- outdated translation 7311938669217173870 -->     <string name="content_description_sliding_handle" msgid="415975056159262248">"Ручка для перасоўвання. Націсніце і ўтрымлівайце."</string>
+    <string name="content_description_sliding_handle" msgid="415975056159262248">"Ручка для перасоўвання. Націсніце і ўтрымлівайце."</string>
     <string name="description_direction_up" msgid="1983114130441878529">"Уверх да <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_down" msgid="4294993639091088240">"Уніз да <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="6814008463839915747">"Улева да <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -1185,29 +1193,29 @@
     <string name="description_target_silent" msgid="893551287746522182">"Ціхі рэжым"</string>
     <string name="description_target_soundon" msgid="30052466675500172">"Гук уключаны"</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Прагартайце, каб разблакаваць."</string>
-    <string name="keyboard_headset_required_to_hear_password" msgid="5913502399391940888">"Каб праслухаць паролi, падключыце гарнiтуру."</string>
+    <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Каб праслухаць паролi, падключыце гарнiтуру."</string>
     <string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Кропка."</string>
     <string name="action_bar_home_description" msgid="5293600496601490216">"Перайсці да пачатковай старонкі"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Перайсці ўверх"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Больш налад"</string>
-    <string name="storage_internal" msgid="7556050805474115618">"Унутраная памяць"</string>
-    <string name="storage_sd_card" msgid="8921771478629812343">"SD-карта"</string>
+    <string name="storage_internal" msgid="4891916833657929263">"Унутраная памяць"</string>
+    <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
-    <string name="extract_edit_menu_button" msgid="302060189057163906">"Рэдагаваць..."</string>
+    <string name="extract_edit_menu_button" msgid="8940478730496610137">"Рэдагаваць"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Папярэджанне выкарыстання дадзеных"</string>
-    <string name="data_usage_warning_body" msgid="7217480745540055170">"Дакраніцеся, каб прагледзець выкарыстанне і налады"</string>
+    <string name="data_usage_warning_body" msgid="2814673551471969954">"Дакраніцеся, каб прагледзець гісторыю выкарыстання і налады."</string>
     <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"Перадача дадз. 2G-3G выключана"</string>
     <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"Перадача дадзеных 4G выключана"</string>
     <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Мабільная перадача дадз. выкл."</string>
     <string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Перад. дадз. Wi-Fi адключаная"</string>
-    <string name="data_usage_limit_body" msgid="4313857592916426843">"Націсніце, каб уключыць"</string>
+    <string name="data_usage_limit_body" msgid="3317964706973601386">"Націсніце, каб уключыць."</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Перавышаны ліміт 2G-3G"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Перавышаны ліміт дадзеных 4G"</string>
     <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Перавышаны ліміт мабільных дадзеных"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Перав. ліміт па дадзеным Wi-Fi"</string>
-    <string name="data_usage_limit_snoozed_body" msgid="2932736326652880660">"<xliff:g id="SIZE">%s</xliff:g> звыш устаноўленай мяжы"</string>
+    <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Аб\'ём <xliff:g id="SIZE">%s</xliff:g> перавышае устаноўл. мяжу."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Зыходныя дадзеныя абмежаваныя"</string>
-    <string name="data_usage_restricted_body" msgid="5087354814839059798">"Націсніце, каб зняць абмежаванне"</string>
+    <string name="data_usage_restricted_body" msgid="6741521330997452990">"Націсніце, каб зняць абмежаванне."</string>
     <string name="ssl_certificate" msgid="6510040486049237639">"Сертыфікат бяспекі"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Гэты сертыфікат сапраўдны."</string>
     <string name="issued_to" msgid="454239480274921032">"Выдадзены:"</string>
@@ -1222,9 +1230,12 @@
     <string name="fingerprints" msgid="4516019619850763049">"Адбіткі пальцаў:"</string>
     <string name="sha256_fingerprint" msgid="4391271286477279263">"Адбітак пальцаў SHA-256:"</string>
     <string name="sha1_fingerprint" msgid="7930330235269404581">"Адбіткі пальцаў SHA-1:"</string>
-    <!-- outdated translation 180268188117163072 -->     <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Глядзець усе..."</string>
-    <!-- outdated translation 3325054276356556835 -->     <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Выберыце дзеянне"</string>
-    <!-- outdated translation 1791316789651185229 -->     <string name="share_action_provider_share_with" msgid="5247684435979149216">"Апублікаваць праз..."</string>
+    <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Прагледзець усё"</string>
+    <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Выберыце працэс"</string>
+    <string name="share_action_provider_share_with" msgid="5247684435979149216">"Апублікаваць з дапамогай"</string>
     <string name="status_bar_device_locked" msgid="3092703448690669768">"Прылада заблакаваная."</string>
     <string name="list_delimeter" msgid="3975117572185494152">", "</string>
+    <string name="sending" msgid="3245653681008218030">"Адпраўка..."</string>
+    <string name="launchBrowserDefault" msgid="2057951947297614725">"Запусцiць браўзер?"</string>
+    <string name="SetupCallDefault" msgid="5834948469253758575">"Прыняць выклік?"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8cc9ba3..23ae6c2 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Разрешава на приложението да прехвърля задачи на преден и на заден план. Злонамерените приложения могат сами да се изведат на преден план без ваша намеса."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"спиране на изпълняваните приложения"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Разрешава на приложението да премахва задачи и да прекратява приложенията им. Злонамерените приложения могат да нарушат поведението на други приложения."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"активиране на отстраняването на грешки в приложения"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Разрешава на приложението да включва отстраняването на грешки за друго приложение. Злонамерените приложения могат да използват това, за да прекратят други приложения."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"промяна на настройките ви за потребителския интерфейс"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Разрешава на приложението да провери дали пакетът може да се инсталира."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обвързване с верификатор на пакета"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Разрешава на притежателя да прави заявки за верификатори на пакета. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"достъп до серийни портове"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Разрешава на притежателя достъп до серийни портове посредством приложния програмен интерфейс (API) SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Искате ли браузърът да запомни тази парола?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не сега"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запомняне"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Подаване на сигнал"</string>
     <string name="wait" msgid="7147118217226317732">"Изчакване"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Страницата не отговаря."\n\n"Искате ли да я затворите?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Приложението се пренасочи"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> се изпълнява."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Първоначално бе стартирано: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4f2aef8..460fcb7 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permet que l\'aplicació desplaci tasques en primer o segon pla. Les aplicacions malicioses poden aparèixer en primer pla sense el teu consentiment."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"atura les aplicacions que s\'estan executant"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet que l\'aplicació elimini tasques i finalitzi les seves aplicacions. Les aplicacions malicioses poden alterar el comportament d\'altres aplicacions."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definició de la compatibilitat de pantalla"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permet que l\'aplicació controli el mode de compatibilitat de pantalla d\'altres aplicacions. És possible que les aplicacions malicioses interrompin el comportament d\'altres aplicacions."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"activa la depuració d\'aplicacions"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permet que una aplicació activi la depuració per a una altra aplicació. Les aplicacions malicioses poden utilitzar aquesta funció per finalitzar altres aplicacions."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"canviar la configuració de la IU"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet que l\'aplicació verifiqui si un paquet es pot instal·lar."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincula a un verificador de paquets"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet que el titular sol·liciti verificadors de paquets. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"accedeix a ports sèrie"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet que el titular accedeixi a ports sèrie amb l\'API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Voleu que el navegador recordi aquesta contrasenya?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ara no"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Recorda-ho"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"D\'acord"</string>
     <string name="report" msgid="4060218260984795706">"Informe"</string>
     <string name="wait" msgid="7147118217226317732">"Espera"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La pàgina ha deixat de respondre."\n\n"Vols tancar-la?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicació redirigida"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> s\'està executant."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> es va iniciar originalment."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index bfcf23f..c801fb4 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Umožňuje aplikaci přesunout úlohy na popředí nebo pozadí. Škodlivé aplikace mohou vynutit zobrazení na popředí bez vašeho svolení."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zastavení činnosti aplikací"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikaci odstranit úlohy a ukončit jejich aplikace. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"povolení ladění aplikací"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Umožňuje aplikaci zapnout ladění jiné aplikace. Škodlivé aplikace mohou toto oprávnění použít k ukončení ostatních aplikací."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"změna vašeho nastavení uživatelského rozhraní"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikaci ověřit, zda balíček lze nainstalovat."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"navázat na ověřovatele balíčků"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteli podávat žádosti o ověření balíčků. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"přístup k sériovým portům"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Umožňuje držiteli přístup k sériovým portům pomocí rozhraní SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prohlížeč zapamatoval toto heslo?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nyní ne"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapamatovat"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Nahlásit"</string>
     <string name="wait" msgid="7147118217226317732">"Počkat"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje."\n\n"Chcete ji zavřít?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Přesměrování aplikace"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Je spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Původně byla spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 67b24bc..65d7cdc 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -140,7 +140,7 @@
     <string name="silent_mode_silent" msgid="319298163018473078">"Ringeren er deaktiveret"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"Ringervibrering"</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"Ringeren er aktiveret"</string>
-    <string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned ..."</string>
+    <string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din tabletcomputer slukkes nu."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon slukkes nu."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Vil du slukke?"</string>
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Tillader, at appen kan flytte opgaver til forgrunden og baggrunden. Ondsindede apps kan tvinge sig selv i forgrunden uden din kontrol."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"stoppe kørsel af apps"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillader, at en app kan fjerne opgaver og lukke deres apps. Ondsindede apps kan forstyrre adfærden for andre apps."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"indstil skærmens kompatibilitet"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Tillader, at appen kontrollerer kompatibilitetstilstanden for skærme i andre applikationer. Ondsindede applikationer kan forstyrre andre applikationers adfærd."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivere fejlretning af appen"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Tillader, at appen kan slå fejlretning til for en anden app. Ondsindede apps kan bruge dette til at afslutte andre apps."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"skift indstillinger for brugergrænsefladen"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillader, at appen kan bekræfte, at en pakke kan installeres."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en bekræftelse af pakker"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillader, at indehaveren kan sende anmodninger om bekræftelser af pakker. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"adgang til serielle porte"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Tillader, at indehaveren kan få adgang til serielle porte ved hjælp af SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nu"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
@@ -881,7 +885,7 @@
     <string name="replace" msgid="5781686059063148930">"Erstat..."</string>
     <string name="delete" msgid="6098684844021697789">"Slet"</string>
     <string name="copyUrl" msgid="2538211579596067402">"Kopier webadresse"</string>
-    <string name="selectTextMode" msgid="1018691815143165326">"Marker tekst"</string>
+    <string name="selectTextMode" msgid="1018691815143165326">"Markér tekst"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekstmarkering"</string>
     <string name="addToDictionary" msgid="9090375111134433012">"føj til ordbog"</string>
     <string name="deleteText" msgid="7070985395199629156">"slet"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapporter"</string>
     <string name="wait" msgid="7147118217226317732">"Vent"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Siden svarer ikke."\n\n"Vil du lukke den?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Appen er omdirigeret"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kører nu."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> blev oprindeligt åbnet."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 7c85323..dbe8137 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ermöglicht der App, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Apps können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"Aktive Apps beenden"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Ermöglicht der App, Aufgaben zu entfernen und die entsprechenden Apps zu beenden. Schädliche Apps können das Verhalten anderer Apps stören."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Bildschirmkompatibilität festlegen"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ermöglicht der App, den Bildschirmkompatibilitätsmodus anderer Apps zu steuern. Schädliche Apps können das Verhalten anderer Apps stören."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"Fehlerbeseitigung für App aktivieren"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ermöglicht der App, die Fehlerbeseitigung für eine andere App zu aktivieren. Schädliche Apps können so andere Apps beenden."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
@@ -684,7 +686,7 @@
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netzwerk gesperrt"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"PUK-Sperre auf SIM"</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Weitere Informationen erhalten Sie im Nutzerhandbuch oder beim Kundendienst."</string>
-    <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Bitte PIN eingeben"</string>
+    <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"PIN eingeben"</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-Karte wird entsperrt..."</string>
     <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Bitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben."\n\n"Bitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ermöglicht der App die Überprüfung, ob ein Paket installiert werden kann"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"An Paketprüfung binden"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ermöglicht dem Halter, Anfragen für die Paketprüfung zu senden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"Zugriff auf serielle Schnittstellen"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Ermöglicht dem Inhaber den Zugriff auf serielle Schnittstellen über das SerialManager-API"</string>
     <string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Bericht"</string>
     <string name="wait" msgid="7147118217226317732">"Warten"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Die Seite reagiert nicht mehr."\n\n"Möchten Sie die Seite schließen?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"App umgeleitet"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird jetzt ausgeführt."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> wurde ursprünglich gestartet."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index aa07f3b..154ca55 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Επιτρέπει στην εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και στο φόντο. Τυχόν κακόβουλες εφαρμογές μπορούν να προωθηθούν στο προσκήνιο χωρίς να μπορείτε να τις ελέγξετε."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"διακοπή εκτέλεσης εφαρμογών"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Επιτρέπει στην εφαρμογή την κατάργηση ενεργειών και την απομάκρυνση των εφαρμογών τους. Τυχόν κακόβουλες εφαρμογές ενδέχεται να διαταράξουν τη λειτουργία άλλων εφαρμογών."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"ενεργοποίηση εντοπισμού σφαλμάτων εφαρμογής"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Επιτρέπει στην εφαρμογή να ενεργοποιήσει τον εντοπισμό σφαλμάτων για μια άλλη εφαρμογή. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τον τερματισμό άλλων εφαρμογών."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"αλλαγή των ρυθμίσεων του UI"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Επιτρέπει στην εφαρμογή να επαληθεύσει τη δυνατότητα εγκατάστασης ενός πακέτου."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"δέσμευση με επαλήθευση πακέτου"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Επιτρέπει στον κάτοχο να υποβάλλει ερωτήματα σε προγράμματα επαλήθευσης πακέτου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"πρόσβαση στις σειριακές θύρες"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Επιτρέπει στον κάτοχο την πρόσβαση στις σειριακές θύρες με τη χρήση του SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Θέλετε το πρόγραμμα περιήγησης να διατηρήσει αυτόν τον κωδικό πρόσβασης;"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Να μην γίνει τώρα"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Διατήρηση"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"ΟΚ"</string>
     <string name="report" msgid="4060218260984795706">"Αναφορά"</string>
     <string name="wait" msgid="7147118217226317732">"Αναμονή"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Η σελίδα δεν ανταποκρίνεται πια."\n\n"Θέλετε να την κλείσετε;"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Ανακατεύθυνση εφαρμογής"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εκτελείται τώρα."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Έγινε εκκίνηση πρώτα της εφαρμογής <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c1f1b40..0429c8b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Allows the app to move tasks to the foreground and background. Malicious apps may force themselves to the front without your control."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"stop running apps"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Allows the app to remove tasks and kill their apps. Malicious apps may disrupt the behaviour of other apps."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"set screen compatibility"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Allows the app to control the screen compatibility mode of other applications. Malicious applications may break the behaviour of other applications."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"enable app debugging"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Allows the app to turn on debugging for another app. Malicious apps may use this to kill other apps."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"change your UI settings"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Allows the app to verify a package is installable."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind to a package verifier"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Do you want the browser to remember this password?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Not now"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Remember"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Report"</string>
     <string name="wait" msgid="7147118217226317732">"Wait"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"The page has become unresponsive."\n\n"Do you want to close it?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"App redirected"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is now running."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was originally launched."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c7f86d0..ad3e949 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -86,8 +86,8 @@
     <string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronización"</string>
     <string name="serviceClassPacket" msgid="6991006557993423453">"Paquete"</string>
     <string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
-    <string name="roamingText0" msgid="7170335472198694945">"Indicador de roaming encendido"</string>
-    <string name="roamingText1" msgid="5314861519752538922">"Indicador de roaming apagado"</string>
+    <string name="roamingText0" msgid="7170335472198694945">"Indicador de roaming activado"</string>
+    <string name="roamingText1" msgid="5314861519752538922">"Indicador de roaming desactivado"</string>
     <string name="roamingText2" msgid="8969929049081268115">"Indicador de roaming titilando"</string>
     <string name="roamingText3" msgid="5148255027043943317">"Fuera del vecindario"</string>
     <string name="roamingText4" msgid="8808456682550796530">"Fuera de construcción"</string>
@@ -97,8 +97,8 @@
     <string name="roamingText8" msgid="5989569778604089291">"Roaming: socio premium"</string>
     <string name="roamingText9" msgid="7969296811355152491">"Roaming: funcionalidad de servicio completa"</string>
     <string name="roamingText10" msgid="3992906999815316417">"Roaming: funcionalidad de servicio parcial"</string>
-    <string name="roamingText11" msgid="4154476854426920970">"Banner de roaming encendido"</string>
-    <string name="roamingText12" msgid="1189071119992726320">"Banner de roaming apagado"</string>
+    <string name="roamingText11" msgid="4154476854426920970">"Banner de roaming activado"</string>
+    <string name="roamingText12" msgid="1189071119992726320">"Banner de roaming desactivado"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Buscando servicio"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -128,13 +128,13 @@
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento de la tableta. Elimina algunos archivos para liberar espacio."</string>
-    <string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
+    <string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del dispositivo. Elimina algunos archivos para liberar espacio."</string>
     <string name="me" msgid="6545696007631404292">"Yo"</string>
     <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opciones de tablet"</string>
-    <string name="power_dialog" product="default" msgid="1319919075463988638">"Opciones de teléfono"</string>
+    <string name="power_dialog" product="default" msgid="1319919075463988638">"Opciones de dispositivo"</string>
     <string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
-    <string name="turn_on_radio" msgid="3912793092339962371">"Encender el teléfono inalámbrico"</string>
-    <string name="turn_off_radio" msgid="8198784949987062346">"Apagar el teléfono inalámbrico"</string>
+    <string name="turn_on_radio" msgid="3912793092339962371">"Activar conexión inalámbrica"</string>
+    <string name="turn_off_radio" msgid="8198784949987062346">"Desactivar conexión inalámbrica"</string>
     <string name="screen_lock" msgid="799094655496098153">"Bloqueo de pantalla"</string>
     <string name="power_off" msgid="4266614107412865048">"Apagar"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"Timbre desactivado"</string>
@@ -142,30 +142,30 @@
     <string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activado"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Apagando…"</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tu tablet se apagará."</string>
-    <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Tu teléfono se apagará."</string>
+    <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Tu dispositivo se apagará."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"¿Deseas apagarlo?"</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"Reciente"</string>
     <string name="no_recent_tasks" msgid="8794906658732193473">"No hay aplicaciones recientes."</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Opciones de tablet"</string>
-    <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones de teléfono"</string>
+    <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones de dispositivo"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
-    <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está Apagado"</string>
-    <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está Encendido"</string>
+    <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está Desactivado"</string>
+    <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está Activado"</string>
     <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
-    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Encendido"</string>
-    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Apagado"</string>
+    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Activado"</string>
+    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Desactivado"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios que te cuestan dinero"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Permite que las aplicaciones realicen actividades con cargo."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
-    <string name="permgroupdesc_messages" msgid="7821999071003699236">"Lee y escribe tus SMS, mensajes de correo electrónico y otros mensajes."</string>
+    <string name="permgroupdesc_messages" msgid="7821999071003699236">"Lee y escribe tus SMS, mensajes de correo y otros mensajes."</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Tu información personal"</string>
-    <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Acceso directo a los contactos y calendario guardados en tu teléfono."</string>
-    <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Acceso directo a tus contactos y calendario guardado en el teléfono."</string>
+    <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Acceso directo a los contactos y calendario guardados en tu dispositivo."</string>
+    <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Acceso directo a tus contactos y calendario guardado en el dispositivo."</string>
     <string name="permgrouplab_location" msgid="635149742436692049">"Tu ubicación"</string>
     <string name="permgroupdesc_location" msgid="5704679763124170100">"Controlar tu ubicación física"</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicación de red"</string>
@@ -173,7 +173,7 @@
     <string name="permgrouplab_accounts" msgid="3359646291125325519">"Tus cuentas"</string>
     <string name="permgroupdesc_accounts" msgid="4948732641827091312">"Acceder a las cuentas disponibles."</string>
     <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controles de hardware"</string>
-    <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acceso directo al hardware en el teléfono."</string>
+    <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acceso directo al hardware en el dispositivo."</string>
     <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Llamadas telefónicas"</string>
     <string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Controlar, grabar y procesar llamadas telefónicas."</string>
     <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Herramientas del sistema"</string>
@@ -203,10 +203,10 @@
     <string name="permdesc_sendSmsNoConfirmation" msgid="3437759207020400204">"Permite que la aplicación envíe mensajes SMS. Las aplicaciones maliciosas pueden generar gastos a causa del envío de mensajes sin tu confirmación."</string>
     <string name="permlab_readSms" msgid="4085333708122372256">"leer SMS o MMS"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2341692916884515613">"Permite que la aplicación lea mensajes SMS almacenados en tu tableta o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
-    <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Permite que la aplicación lea mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
+    <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Permite que la aplicación lea mensajes SMS almacenados en tu dispositivo o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
     <string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS o MMS"</string>
     <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Permite que la aplicación escriba en mensajes SMS almacenados en tu tableta o tarjeta SIM. Las aplicaciones maliciosas pueden eliminar tus mensajes."</string>
-    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Permite que la aplicación escriba en mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden eliminar tus mensajes."</string>
+    <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Permite que la aplicación escriba en mensajes SMS almacenados en tu dispositivo o tarjeta SIM. Las aplicaciones maliciosas pueden eliminar tus mensajes."</string>
     <string name="permlab_receiveWapPush" msgid="8258226427716551388">"recibir WAP"</string>
     <string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Permite que la aplicación reciba y procese mensajes WAP. Las aplicaciones maliciosas pueden controlar tus mensajes o eliminarlos sin mostrártelos."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicaciones en ejecución"</string>
@@ -215,11 +215,13 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas al primero o segundo plano. Las aplicaciones maliciosas pueden forzar su paso al primer plano sin que tú las controles."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"detener las aplicaciones en ejecución"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación elimine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
-    <string name="permlab_setDebugApp" msgid="3022107198686584052">"habilitar depuración de aplicación"</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Configurar el modo de la compatibilidad de otras pantalla"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite a la aplicación controlar el modo de la compatibilidad de las pantallas de otras aplicaciones. Las aplicaciones malintencionadas pueden interrumpir el funcionamiento de otras aplicaciones."</string>
+    <string name="permlab_setDebugApp" msgid="3022107198686584052">"activar depuración de aplicación"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar tu configuración de la interfaz de usuario"</string>
     <string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Permite que la aplicación cambie la configuración actual como, por ejemplo, la configuración regional o el tamaño de fuente general."</string>
-    <string name="permlab_enableCarMode" msgid="5684504058192921098">"habilitar el modo de auto"</string>
+    <string name="permlab_enableCarMode" msgid="5684504058192921098">"activar el modo de auto"</string>
     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permite que la aplicación habilite el modo coche."</string>
     <string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"eliminar los procesos de fondo"</string>
     <string name="permdesc_killBackgroundProcesses" msgid="931129103262126617">"Permite que la aplicación elimine procesos de otras aplicaciones que se ejecutan en segundo plano, aunque haya suficiente memoria."</string>
@@ -263,7 +265,7 @@
     <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Permite que la aplicación cree y administre sus propios tokens al ignorar su orden z normal. Las aplicaciones normales no deben utilizar este permiso."</string>
     <string name="permlab_injectEvents" msgid="1378746584023586600">"presionar teclas y botones de control"</string>
     <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Permite que la aplicación ofrezca sus propios eventos de entrada (pulsaciones de teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizar este permiso para controlar la tableta."</string>
-    <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Permite que la aplicación ofrezca sus propios eventos de entrada (pulsaciones de teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizar este permiso para controlar el teléfono."</string>
+    <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Permite que la aplicación ofrezca sus propios eventos de entrada (pulsaciones de teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizar este permiso para controlar el dispositivo."</string>
     <string name="permlab_readInputState" msgid="469428900041249234">"grabar tu tipo y las medidas que tomes"</string>
     <string name="permdesc_readInputState" msgid="8387754901688728043">"Permite que la aplicación observe las teclas que presionas, incluso al interactuar con otra aplicación (como cuando escribes una contraseña). Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a un método de entrada"</string>
@@ -298,19 +300,19 @@
     <string name="permdesc_installPackages" msgid="5628530972548071284">"Permite que la aplicación instale paquetes de Android nuevos o actualizados. Las aplicaciones maliciosas pueden utilizar este permiso para agregar nuevas aplicaciones con permisos arbitrarios potentes."</string>
     <string name="permlab_clearAppCache" msgid="7487279391723526815">"eliminar todos los datos de caché de la aplicación"</string>
     <string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Permite que la aplicación libere almacenamiento en la tableta al eliminar archivos en el directorio caché de la aplicación. El acceso al proceso del sistema suele ser muy restringido."</string>
-    <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Permite que la aplicación libere espacio de almacenamiento en el teléfono al eliminar archivos en el directorio caché de la aplicación. El acceso al proceso del sistema suele ser muy restringido."</string>
+    <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Permite que la aplicación libere espacio de almacenamiento en el dispositivo al eliminar archivos en el directorio caché de la aplicación. El acceso al proceso del sistema suele ser muy restringido."</string>
     <string name="permlab_movePackage" msgid="3289890271645921411">"mover recursos de la aplicación"</string>
     <string name="permdesc_movePackage" msgid="319562217778244524">"Permite que la aplicación traslade recursos de la aplicación de medios internos a medios externos y viceversa."</string>
     <string name="permlab_readLogs" msgid="6615778543198967614">"lee los datos confidenciales del registro"</string>
     <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Permite que la aplicación lea diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con la tableta, lo que podría incluir información personal o privada."</string>
-    <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Permite que la aplicación lea los diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con el teléfono, que puede incluir información personal o privada."</string>
+    <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Permite que la aplicación lea los diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con el dispositivo, que puede incluir información personal o privada."</string>
     <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"Usar cualquier decodificador de medios para la reproducción"</string>
     <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar la seguridad y estabilidad del sistema. SOLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activar o desactivar componentes de la aplicación"</string>
-    <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Permite que la aplicación determine si un componente de otra aplicación está habilitado o no. Las aplicaciones maliciosas pueden utilizar este permiso para inhabilitar funciones importantes de la tableta. Es necesario ser precavido con este permiso, ya que es posible que los componentes de la aplicación queden inservibles, incoherentes o inestables."</string>
-    <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Permite que la aplicación determine si un componente de otra aplicación está habilitado o no. Las aplicaciones maliciosas pueden utilizar este permiso para inhabilitar funciones importantes del teléfono. Es necesario ser precavido con este permiso, ya que es posible que los componentes de la aplicación queden inservibles, incoherentes o inestables."</string>
+    <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Permite que la aplicación determine si un componente de otra aplicación está habilitado o no. Las aplicaciones maliciosas pueden utilizar este permiso para desactivar funciones importantes de la tableta. Es necesario ser precavido con este permiso, ya que es posible que los componentes de la aplicación queden inservibles, incoherentes o inestables."</string>
+    <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Permite que la aplicación determine si un componente de otra aplicación está habilitado o no. Las aplicaciones maliciosas pueden utilizar este permiso para desactivar funciones importantes del dispositivo. Es necesario ser precavido con este permiso, ya que es posible que los componentes de la aplicación queden inservibles, incoherentes o inestables."</string>
     <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"establecer aplicaciones preferidas"</string>
     <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Permite que la aplicación modifique tus aplicaciones preferidas. Las aplicaciones maliciosas pueden modificar sin aviso las aplicaciones que se ejecutan y así engañar a tus aplicaciones existentes para que recopilen tu información privada."</string>
     <string name="permlab_writeSettings" msgid="1365523497395143704">"modificar la configuración global del sistema"</string>
@@ -321,16 +323,16 @@
     <string name="permdesc_writeGservices" msgid="1287309437638380229">"Permite que la aplicación modifique el mapa de servicios de Google. Las aplicaciones normales no deben utilizar este permiso."</string>
     <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"ejecutar automáticamente al iniciar"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Permite que la aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que la tableta tarde más en inicializarse y que la aplicación ralentice el funcionamiento general de la tableta al estar en ejecución constante."</string>
-    <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Permite que la aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que el teléfono tarde más en inicializarse y que la aplicación ralentice el funcionamiento general del teléfono al estar en ejecución constante."</string>
+    <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Permite que la aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que el dispositivo tarde más en inicializarse y que la aplicación ralentice el funcionamiento general del dispositivo al estar en ejecución constante."</string>
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar emisiones pegajosas"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="1181582512022829259">"Permite que la aplicación envíe transmisiones persistentes que permanecen luego de que finaliza la transmisión. Las aplicaciones maliciosas pueden hacer que la tableta funcione más lentamente o de manera inestable al forzarla a utilizar mucha memoria."</string>
-    <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Permite que la aplicación envíe transmisiones persistentes que permanecen luego de que finaliza la transmisión. Las aplicaciones maliciosas pueden hacer que el teléfono funcione más lento o de manera inestable al forzarlo a utilizar mucha memoria."</string>
+    <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Permite que la aplicación envíe transmisiones persistentes que permanecen luego de que finaliza la transmisión. Las aplicaciones maliciosas pueden hacer que el dispositivo funcione más lento o de manera inestable al forzarlo a utilizar mucha memoria."</string>
     <string name="permlab_readContacts" msgid="6219652189510218240">"leer datos de contacto"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="4028657556924039119">"Permite que la aplicación lea todos los datos de contacto (direcciones) almacenados en tu tableta. Las aplicaciones maliciosas pueden usar este permiso para enviar tus datos a otras personas."</string>
-    <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Permite que la aplicación lea todos los datos de contacto (direcciones) almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizar este permiso para enviar tus datos a otro teléfono."</string>
+    <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Permite que la aplicación lea todos los datos de contacto (direcciones) almacenados en tu dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para enviar tus datos a otro dispositivo."</string>
     <string name="permlab_writeContacts" msgid="644616215860933284">"escribir datos de contacto"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Permite que la aplicación modifique la información de contacto (dirección) almacenada en tu tableta. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar tu información de contacto."</string>
-    <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Permite que la aplicación modifique la información de contacto (dirección) almacenada en tu teléfono. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar tu información de contacto."</string>
+    <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Permite que la aplicación modifique la información de contacto (dirección) almacenada en tu dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar tu información de contacto."</string>
     <string name="permlab_readProfile" msgid="6824681438529842282">"Leer tus datos de perfil"</string>
     <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"Permite que la aplicación lea la información de perfil almacenada en tu dispositivo, como tu nombre e información de contacto. Esto significa que la aplicación puede identificarte y enviar tu información de perfil a otros."</string>
     <string name="permlab_writeProfile" msgid="4679878325177177400">"Escrib. en datos de tu perfil"</string>
@@ -341,8 +343,8 @@
     <string name="permdesc_writeSocialStream" product="default" msgid="3496277176955721451">"Permite que la aplicación muestre las actualizaciones sociales de tus amigos. Las aplicaciones maliciosas pueden usar este permiso para hacerse pasar por un amigo y engañarte para que reveles contraseñas u otros datos confidenciales."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"Leer eventos de calendario e información confidencial"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Permite que la aplicación lea todos los eventos del calendario almacenados en tu tableta, incluidos los de amigos o compañeros de trabajo. Las aplicaciones maliciosas pueden extraer información personal de esos calendarios sin que los propietarios lo sepan."</string>
-    <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Permite que la aplicación lea todos los eventos del calendario almacenados en tu teléfono, incluidos los de amigos o compañeros de trabajo. Las aplicaciones maliciosas pueden extraer información personal de esos calendarios sin que los propietarios lo sepan."</string>
-    <string name="permlab_writeCalendar" msgid="8438874755193825647">"Agregar o modificar los eventos de calendario y enviar un correo electrónico a los invitados sin que los propietarios lo sepan"</string>
+    <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Permite que la aplicación lea todos los eventos del calendario almacenados en tu dispositivo, incluidos los de amigos o compañeros de trabajo. Las aplicaciones maliciosas pueden extraer información personal de esos calendarios sin que los propietarios lo sepan."</string>
+    <string name="permlab_writeCalendar" msgid="8438874755193825647">"Agregar o modificar los eventos de calendario y enviar un correo a los invitados sin que los propietarios lo sepan"</string>
     <string name="permdesc_writeCalendar" msgid="2243771395254848873">"Permite que la aplicación envíe invitaciones a eventos como propietario del calendario, y que agregue, elimine y cambie eventos que puedes modificar en tu dispositivo, incluidos los de tus amigos o compañeros de trabajo. Las aplicaciones maliciosas pueden enviar correos electrónicos de spam que aparenten provenir de propietarios de calendarios, modificar eventos sin que el propietario lo sepa o agregar eventos falsos."</string>
     <string name="permlab_accessMockLocation" msgid="8688334974036823330">"crear fuentes de ubicación de prueba"</string>
     <string name="permdesc_accessMockLocation" msgid="7577931556422993949">"Permite que la aplicación cree fuentes de ubicación simuladas para pruebas. Las aplicaciones maliciosas pueden utilizar este permiso para anular la ubicación o el estado que devuelven las fuentes de ubicación actuales, como los proveedores de GPS o redes."</string>
@@ -352,10 +354,10 @@
     <string name="permdesc_installLocationProvider" msgid="1742577679350078373">"Crear fuentes de ubicación simuladas para pruebas. Las aplicaciones maliciosas pueden utilizar esta opción para anular la ubicación o el estado que devuelven las fuentes de ubicación reales, como los proveedores de GPS o redes, o para monitorear e informar tu ubicación a una fuente externa."</string>
     <string name="permlab_accessFineLocation" msgid="8116127007541369477">"ubicación precisa (GPS)"</string>
     <string name="permdesc_accessFineLocation" product="tablet" msgid="5326423948268164934">"Permite acceder a las fuentes de ubicación precisas, como el sistema de posicionamiento global en la tableta, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar dónde te encuentras y pueden consumir batería adicional."</string>
-    <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Permite acceder a las fuentes de ubicación precisa, como el sistema de posicionamiento global del teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar dónde te encuentras y pueden consumir batería adicional."</string>
+    <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Permite acceder a las fuentes de ubicación precisa, como el sistema de posicionamiento global del dispositivo, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar dónde te encuentras y pueden consumir batería adicional."</string>
     <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ubicación aproximada (basada en la red)"</string>
     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="5460726396318105483">"Permite acceder a las fuentes de ubicación aproximada, como la base de datos de la red para celulares, para determinar la ubicación aproximada de una tableta, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar tu ubicación aproximada."</string>
-    <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"Permite acceder a fuentes de ubicación aproximada como, por ejemplo, la base de datos de la red para celulares, para determinar la ubicación aproximada de un teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar tu ubicación aproximada."</string>
+    <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"Permite acceder a fuentes de ubicación aproximada como, por ejemplo, la base de datos de la red para celulares, para determinar la ubicación aproximada de un dispositivo, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar tu ubicación aproximada."</string>
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acceder a SurfaceFlinger"</string>
     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que la aplicación utilice funciones de SurfaceFlinger de bajo nivel."</string>
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer el búfer de tramas"</string>
@@ -366,14 +368,14 @@
     <string name="permdesc_recordAudio" msgid="2387462233976248635">"Permite que la aplicación acceda a la ruta de grabación de audio."</string>
     <string name="permlab_camera" msgid="3616391919559751192">"tomar fotografías y grabar videos"</string>
     <string name="permdesc_camera" msgid="1507407407002492176">"Permite que la aplicación tome fotografías y grabe videos con la cámara. De este modo, la aplicación puede obtener las imágenes que capta la cámara en cualquier momento."</string>
-    <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"inhabilitar tablet de forma permanente"</string>
-    <string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar teléfono de manera permanente"</string>
+    <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactivar tablet de forma permanente"</string>
+    <string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar dispositivo de manera permanente"</string>
     <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Permite que la aplicación inhabilite toda la tableta de manera permanente. Esto es muy peligroso."</string>
-    <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Permite que la aplicación inhabilite el teléfono de forma permanente. Este permiso es muy peligroso."</string>
+    <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Permite que la aplicación inhabilite el dispositivo de forma permanente. Este permiso es muy peligroso."</string>
     <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"forzar reinicio del tablet"</string>
-    <string name="permlab_reboot" product="default" msgid="2898560872462638242">"forzar reinicio del teléfono"</string>
+    <string name="permlab_reboot" product="default" msgid="2898560872462638242">"forzar reinicio del dispositivo"</string>
     <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"Permite que la aplicación provoque el reinicio de la tableta."</string>
-    <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Permite que la aplicación fuerce el reinicio del teléfono."</string>
+    <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Permite que la aplicación fuerce el reinicio del dispositivo."</string>
     <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar y desmontar filesystems"</string>
     <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"Permite que la aplicación active y desactive sistemas de archivos para un almacenamiento extraíble."</string>
     <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"espacio de almacenamiento externo del formato"</string>
@@ -403,7 +405,7 @@
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"llamar directamente a cualquier número de teléfono"</string>
     <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Permite que la aplicación llame a cualquier número de teléfono, incluidos números de emergencia, sin tu intervención. Las aplicaciones maliciosas pueden realizar llamadas innecesarias e ilegales a servicios de emergencia."</string>
     <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"iniciar directamente la configuración CDMA del tablet"</string>
-    <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente la configuración CDMA del teléfono"</string>
+    <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente la configuración CDMA del dispositivo"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permite que la aplicación inicie el método de acceso CDMA. Las aplicaciones maliciosas pueden iniciar el método CDMA de forma innecesaria."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de ubicación"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permite que la aplicación habilite/deshabilite notificaciones de actualización de ubicación de la radio. Las aplicaciones normales no deben utilizar este permiso."</string>
@@ -411,21 +413,21 @@
     <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Permite que la aplicación lea/escriba el acceso a propiedades subidas por el servicio de registro. Las aplicaciones normales no deben usar este permiso."</string>
     <string name="permlab_bindGadget" msgid="776905339015863471">"elegir widgets"</string>
     <string name="permdesc_bindGadget" msgid="8261326938599049290">"Permite que la aplicación le indique al sistema qué widgets se pueden utilizar con cada aplicación. Una aplicación con este permiso puede proporcionar acceso a información personal por parte de otras aplicaciones. Las aplicaciones normales no deben utilizar este permiso."</string>
-    <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar el estado del teléfono"</string>
+    <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar el estado del dispositivo"</string>
     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, encender y apagar la radio del teléfono y tareas similares sin siquiera notificártelo."</string>
-    <string name="permlab_readPhoneState" msgid="2326172951448691631">"leer el estado del teléfono y la identidad"</string>
+    <string name="permlab_readPhoneState" msgid="2326172951448691631">"leer el estado del dispositivo y la identidad"</string>
     <string name="permdesc_readPhoneState" msgid="5127767618743602782">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. Una aplicación con este permiso puede determinar el número de teléfono y el número de serie del teléfono, si hay una llamada activa, el número al que esa llamada está conectada, etc."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar que el tablet entre en estado de inactividad"</string>
-    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el teléfono entre en estado de inactividad"</string>
+    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el dispositivo entre en estado de inactividad"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación evite que la tableta entre en estado de inactividad."</string>
-    <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que la aplicación evite que el teléfono entre en estado de inactividad."</string>
+    <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que la aplicación evite que el dispositivo entre en estado de inactividad."</string>
     <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"apagar o encender el tablet"</string>
-    <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"apagar o encender el teléfono"</string>
+    <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"apagar o encender el dispositivo"</string>
     <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que la aplicación encienda o apague la tableta."</string>
-    <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Permite que la aplicación encienda o apague el teléfono."</string>
+    <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Permite que la aplicación encienda o apague el dispositivo."</string>
     <string name="permlab_factoryTest" msgid="3715225492696416187">"ejecutar en el modo de prueba de fábrica"</string>
     <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del tablet. Sólo disponible cuando el tablet se ejecuta en el modo de prueba de fábrica."</string>
-    <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del teléfono. Sólo disponible cuando un teléfono se ejecuta en el modo de prueba de fábrica."</string>
+    <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del dispositivo. Sólo disponible cuando un dispositivo se ejecuta en el modo de prueba de fábrica."</string>
     <string name="permlab_setWallpaper" msgid="6627192333373465143">"establecer papel tapiz"</string>
     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Permite que la aplicación establezca el fondo de pantalla del sistema."</string>
     <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"establecer sugerencias de tamaño del papel tapiz"</string>
@@ -434,15 +436,15 @@
     <string name="permdesc_masterClear" msgid="3665380492633910226">"Permite que la aplicación restablezca por completo el sistema a su configuración de fábrica al eliminar todos los datos, la configuración y las aplicaciones instaladas."</string>
     <string name="permlab_setTime" msgid="2021614829591775646">"establecer la hora"</string>
     <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Permite que la aplicación cambie la hora del reloj de la tableta."</string>
-    <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Permite que la aplicación cambie la hora del reloj del teléfono."</string>
+    <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Permite que la aplicación cambie la hora del reloj del dispositivo."</string>
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"establecer zona horaria"</string>
     <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Permite que la aplicación cambie la zona horaria de la tableta."</string>
-    <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Permite que la aplicación cambie la zona horaria del teléfono."</string>
+    <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Permite que la aplicación cambie la zona horaria del dispositivo."</string>
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"actuar como cuenta, administrador o servicio"</string>
     <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Permite que la aplicación haga llamadas a los autenticadores de cuentas."</string>
     <string name="permlab_getAccounts" msgid="4549918644233460103">"descubrir cuentas conocidas"</string>
     <string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Permite que la aplicación obtenga una lista de cuentas reconocidas por la tableta."</string>
-    <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Permite que la aplicación obtenga una lista de cuentas reconocidas por el teléfono."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Permite que la aplicación obtenga una lista de cuentas reconocidas por el dispositivo."</string>
     <string name="permlab_authenticateAccounts" msgid="3940505577982882450">"actuar como autenticador de cuenta"</string>
     <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Permite que la aplicación utilice las capacidades del autenticador de cuentas del administrador de cuentas, incluida la creación de cuentas y la obtención y configuración de sus contraseñas."</string>
     <string name="permlab_manageAccounts" msgid="4440380488312204365">"administrar la lista de cuentas"</string>
@@ -469,18 +471,18 @@
     <string name="permdesc_changeWifiMulticastState" msgid="7633598524564320817">"Permite que la aplicación reciba paquetes que no están dirigidos directamente a tu dispositivo. Esto puede ser útil para descubrir servicios cercanos. Utiliza más energia que el modo que no es de multidifusión."</string>
     <string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"Administración de Bluetooth"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permite que la aplicación configure la tableta Bluetooth local y descubra y se sincronice con dispositivos remotos."</string>
-    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite que la aplicación configure el teléfono Bluetooth local y descubra y se sincronice con dispositivos remotos."</string>
+    <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite que la aplicación configure el dispositivo Bluetooth local y descubra y se sincronice con dispositivos remotos."</string>
     <string name="permlab_accessWimaxState" msgid="1232061307208861588">"Ver el estado de WiMAX"</string>
     <string name="permdesc_accessWimaxState" msgid="5914958077555177749">"Permite que la aplicación consulte la información sobre el estado de WiMAX."</string>
     <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar el estado de WiMAX"</string>
     <string name="permdesc_changeWimaxState" msgid="3328853825006455912">"Permite que la aplicación se conecte a una red WiMAX y se desconecte de ella."</string>
     <string name="permlab_bluetooth" msgid="8361038707857018732">"crear conexiones de Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Permite que la aplicación vea la configuración de la tableta Bluetooth local, y que cree y acepte conexiones con los dispositivos sincronizados."</string>
-    <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Permite que la aplicación vea la configuración del teléfono Bluetooth local, y que cree y acepte conexiones con los dispositivos sincronizados."</string>
+    <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Permite que la aplicación vea la configuración del dispositivo Bluetooth local, y que cree y acepte conexiones con los dispositivos sincronizados."</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"controlar la Transmisión de datos en proximidad"</string>
     <string name="permdesc_nfc" msgid="7120611819401789907">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string>
     <string name="permlab_disableKeyguard" msgid="4977406164311535092">"desactivar el bloqueo"</string>
-    <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Permite que la aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Un ejemplo de este permiso es la inhabilitación por parte del teléfono del bloqueo del teclado al recibir una llamada telefónica entrante y su posterior habilitación cuando finaliza la llamada."</string>
+    <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Permite que la aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Un ejemplo de este permiso es la inhabilitación por parte del dispositivo del bloqueo del teclado al recibir una llamada telefónica entrante y su posterior habilitación cuando finaliza la llamada."</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
     <string name="permdesc_readSyncSettings" msgid="5464056785274229278">"Permite que la aplicación lea la configuración de sincronización; por ejemplo, si está habilitada la sincronización para la aplicación Personas."</string>
     <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"escribir configuración de sincronización"</string>
@@ -515,14 +517,14 @@
     <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Controla la cantidad de contraseñas incorrectas ingresadas al desbloquear la pantalla y bloquea la tableta o borra todos los datos de la tableta si se ingresaron demasiadas contraseñas incorrectas."</string>
-    <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Controla la cantidad de contraseñas ingresadas incorrectamente al desbloquear la pantalla y bloquea el teléfono o borra todos sus datos si se ingresan demasiadas contraseñas incorrectas."</string>
+    <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Controla la cantidad de contraseñas ingresadas incorrectamente al desbloquear la pantalla y bloquea el dispositivo o borra todos sus datos si se ingresan demasiadas contraseñas incorrectas."</string>
     <string name="policylab_resetPassword" msgid="2620077191242688955">"Cambiar la contraseña para desbloquear la pantalla"</string>
     <string name="policydesc_resetPassword" msgid="605963962301904458">"Cambiar la contraseña para desbloquear la pantalla"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bloquear la pantalla"</string>
     <string name="policydesc_forceLock" msgid="1141797588403827138">"Controlar cómo y cuándo se bloquea la pantalla"</string>
-    <string name="policylab_wipeData" msgid="3910545446758639713">"Borrar todos los datos"</string>
-    <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Borrar los datos de la tableta sin avisar y restablecer la configuración de fábrica"</string>
-    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Borrar los datos del teléfono sin avisar y restablecer la configuración de fábrica"</string>
+    <string name="policylab_wipeData" msgid="3910545446758639713">"Eliminar todos los datos"</string>
+    <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Eliminar los datos de la tableta sin avisar y restablecer la configuración de fábrica"</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Eliminar los datos del dispositivo sin avisar y restablecer la configuración de fábrica"</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Configura el proxy global de dispositivo"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configuración del proxy global de dispositivo que se utilizará mientras se habilita la política. Sólo la primera administración de dispositivo configura el proxy global efectivo."</string>
     <string name="policylab_expirePassword" msgid="885279151847254056">"Establecer la caducidad del bloqueo de pantalla"</string>
@@ -629,7 +631,7 @@
     <string name="relationTypeAssistant" msgid="6274334825195379076">"Asistente"</string>
     <string name="relationTypeBrother" msgid="8757913506784067713">"Hermano"</string>
     <string name="relationTypeChild" msgid="1890746277276881626">"Hijo"</string>
-    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Conviviente"</string>
+    <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Pareja de hecho"</string>
     <string name="relationTypeFather" msgid="5228034687082050725">"Padre"</string>
     <string name="relationTypeFriend" msgid="7313106762483391262">"Amigo"</string>
     <string name="relationTypeManager" msgid="6365677861610137895">"Gerente"</string>
@@ -671,7 +673,7 @@
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"No hay tarjeta SIM."</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No hay tarjeta SIM en el tablet."</string>
-    <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No hay tarjeta SIM en el teléfono."</string>
+    <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No hay tarjeta SIM en el dispositivo."</string>
     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inserta una tarjeta SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Falta la tarjeta SIM o no se puede leer. Introduce una tarjeta SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Tu tarjeta SIM se ha inhabilitado de forma permanente."\n" Ponte en contacto con tu proveedor de servicios inalámbricos para obtener otra tarjeta SIM."</string>
@@ -690,27 +692,27 @@
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu tableta mediante el uso de tu información de acceso de Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono mediante el uso de tu información de acceso de Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu dispositivo mediante el uso de tu información de acceso de Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Intentaste desbloquear la tableta <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica de la tableta y se pierdan todos los datos de usuario."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica del teléfono y se pierdan todos los datos de usuario."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica del dispositivo y se pierdan todos los datos de usuario."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Intentaste desbloquear la tableta <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica de la tableta."</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica del teléfono."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica del dispositivo."</string>
     <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Olvidaste el patrón?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Desbloquear cuenta"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Demasiados intentos incorrectos de creación del patrón"</string>
     <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Para desbloquear, accede con tu cuenta de Google."</string>
-    <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nombre de usuario (correo electrónico)"</string>
+    <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nombre de usuario (correo)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Contraseña"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inicia sesión"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nombre de usuario o contraseña incorrecta."</string>
     <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"¿Olvidaste tu nombre de usuario o contraseña?"\n"Accede a "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Comprobando..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Desbloquear"</string>
-    <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sonido encendido"</string>
-    <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Sonido apagado"</string>
+    <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sonido activado"</string>
+    <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Sonido desactivado"</string>
     <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Se inició el patrón"</string>
-    <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Se borró el patrón"</string>
+    <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Se eliminó el patrón"</string>
     <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Se agregó una celda."</string>
     <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Se completó el patrón"</string>
     <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
@@ -749,7 +751,7 @@
     <string name="permdesc_readHistoryBookmarks" msgid="4577476392604595921">"Permite que la aplicación consulte todos los marcadores del navegador y todas las URL que haya visitado."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"escribir historial y marcadores del navegador"</string>
     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="1757103804824209530">"Permite que la aplicación modifique el historial o los marcadores del navegador guardados en tu tableta. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar los datos de tu navegador."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"Permite que la aplicación modifique el historial o los marcadores del navegador guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar los datos de tu navegador."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"Permite que la aplicación modifique el historial o los marcadores del navegador guardados en tu dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar los datos de tu navegador."</string>
     <string name="permlab_setAlarm" msgid="5924401328803615165">"configurar alarma en reloj alarma"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite que la aplicación establezca una alarma en una aplicación de alarma instalada. Es posible que algunas aplicaciones de alarma no incluyan esta función."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"agregar correo de voz"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Vincular a un verificador de paquetes"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que el titular solicite verificadores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"Acceder a los puertos serie"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de la API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"¿Quieres recordar esta contraseña en el navegador?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no."</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Recuerda"</string>
@@ -774,7 +778,7 @@
     <string name="search_go" msgid="8298016669822141719">"Buscar"</string>
     <string name="searchview_description_search" msgid="6749826639098512120">"Buscar"</string>
     <string name="searchview_description_query" msgid="5911778593125355124">"Consulta de búsqueda"</string>
-    <string name="searchview_description_clear" msgid="1330281990951833033">"Borrar la consulta"</string>
+    <string name="searchview_description_clear" msgid="1330281990951833033">"Eliminar la consulta"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Enviar consulta"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Búsqueda por voz"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"hace 1 mes"</string>
@@ -848,7 +852,7 @@
     <item quantity="one" msgid="2178576254385739855">"mañana"</item>
     <item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
   </plurals>
-    <string name="preposition_for_date" msgid="9093949757757445117">"encendido <xliff:g id="DATE">%s</xliff:g>"</string>
+    <string name="preposition_for_date" msgid="9093949757757445117">"activado <xliff:g id="DATE">%s</xliff:g>"</string>
     <string name="preposition_for_time" msgid="5506831244263083793">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
     <string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
     <string name="day" msgid="8144195776058119424">"día"</string>
@@ -889,7 +893,7 @@
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
     <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Poco espacio de almacenamiento"</string>
     <string name="low_internal_storage_view_text" product="tablet" msgid="4231085657068852042">"Está quedando poco espacio de almacenamiento en el tablet."</string>
-    <string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Hay poco espacio de almacenamiento en el teléfono."</string>
+    <string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Hay poco espacio de almacenamiento en el dispositivo."</string>
     <string name="ok" msgid="5970060430562524910">"Aceptar"</string>
     <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
     <string name="yes" msgid="5362982303337969312">"Aceptar"</string>
@@ -900,7 +904,7 @@
     <string name="capital_off" msgid="6815870386972805832">"No"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Completar la acción mediante"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utilizar de manera predeterminada en esta acción."</string>
-    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Borrar valores predeterminados en Configuración del sistema &gt; Aplicaciones &gt; Descargas."</string>
+    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Eliminar valores predeterminados en Configuración del sistema &gt; Aplicaciones &gt; Descargas."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Seleccionar una acción"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"Selecciona una aplicación para el dispositivo USB."</string>
     <string name="noApplications" msgid="2991814273936504689">"Ninguna aplicación puede realizar esta acción."</string>
@@ -915,12 +919,13 @@
     <string name="force_close" msgid="8346072094521265605">"Aceptar"</string>
     <string name="report" msgid="4060218260984795706">"Notificar"</string>
     <string name="wait" msgid="7147118217226317732">"Esperar"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La página no responde."\n\n"¿Deseas cerrarla?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicación redireccionada"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando ahora."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> se inició originalmente."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
-    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volver a habilitar Configuración del sistema &gt; Aplicaciones &gt; Descargas"</string>
+    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volver a activar Configuración del sistema &gt; Aplicaciones &gt; Descargas"</string>
     <string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode de aplicación automática."</string>
     <string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha violado su política StrictMode autoimpuesta."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android se está actualizando..."</string>
@@ -1031,7 +1036,7 @@
     <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Se perderán todos los datos de tu tarjeta."</string>
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formato"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración de USB conectada"</string>
-    <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para inhabilitar la depuración de USB."</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para desactivar la depuración de USB."</string>
     <string name="select_input_method" msgid="4653387336791222978">"Selecciona el método de introducción"</string>
     <string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introducción"</string>
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1203,7 +1208,7 @@
     <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"Datos de 4 GB desactivados"</string>
     <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Datos móviles desactivados"</string>
     <string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Datos Wi-Fi desactivados"</string>
-    <string name="data_usage_limit_body" msgid="3317964706973601386">"Toca para habilitar."</string>
+    <string name="data_usage_limit_body" msgid="3317964706973601386">"Toca para activar."</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Supera límite de datos de 2G-3G"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Límite de datos de 4G superado"</string>
     <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Límite de datos móviles superado"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index fe6c704..1bd13bd 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas a segundo o a primer plano. Algunas aplicaciones malintencionadas pueden aparecer en primer plano sin el control del usuario."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"detener aplicaciones en ejecución"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación termine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"establecer compatibilidad de pantalla"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite que la aplicación controle el modo de compatibilidad de la pantalla de otras aplicaciones. Las aplicaciones malintencionadas pueden influir de forma negativa en el funcionamiento de otras aplicaciones."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"habilitar depuración de aplicación"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar la configuración de la interfaz de usuario"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"enlazar con un detector de paquetes"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que se envíen solicitudes de detectores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"acceder a puertos serie"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"¿Quieres que el navegador recuerde esta contraseña?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Recordar"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"Aceptar"</string>
     <string name="report" msgid="4060218260984795706">"Informar"</string>
     <string name="wait" msgid="7147118217226317732">"Esperar"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La página no responde."\n\n"¿Quieres cerrarla?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicación redireccionada"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Inicialmente, se inició la aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 1a86b9d..2f42a70 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -73,11 +73,11 @@
     <string name="RestrictedOnData" msgid="8653794784690065540">"Andmesideteenus on blokeeritud."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hädaabiteenus on blokeeritud."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Häälteenus on blokeeritud."</string>
-    <string name="RestrictedOnAllVoice" msgid="1459318899842232234">"Kõik häälteenused on blokeeritud."</string>
+    <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"Kõik häälteenused on blokeeritud."</string>
     <string name="RestrictedOnSms" msgid="8314352327461638897">"SMS-teenus on blokeeritud."</string>
-    <string name="RestrictedOnVoiceData" msgid="8244438624660371717">"Hääl-/andmeteenused on blokeeritud."</string>
+    <string name="RestrictedOnVoiceData" msgid="996636487106171320">"Hääl-/andmeteenused on blokeeritud."</string>
     <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Hääl-/SMS-teenused on blokeeritud."</string>
-    <string name="RestrictedOnAll" msgid="2714924667937117304">"Kõik hääl-/andme-/SMS-teenused on blokeeritud."</string>
+    <string name="RestrictedOnAll" msgid="5643028264466092821">"Kõik hääl-/andme-/SMS-teenused on blokeeritud."</string>
     <string name="serviceClassVoice" msgid="1258393812335258019">"Hääl"</string>
     <string name="serviceClassData" msgid="872456782077937893">"Andmed"</string>
     <string name="serviceClassFAX" msgid="5566624998840486475">"FAKS"</string>
@@ -108,27 +108,27 @@
     <string name="fcComplete" msgid="3118848230966886575">"Funktsioonikood valmis."</string>
     <string name="fcError" msgid="3327560126588500777">"Ühendusprobleem või kehtetu funktsioonikood."</string>
     <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
-    <string name="httpError" msgid="6603022914760066338">"Ilmnes võrgu viga."</string>
-    <string name="httpErrorLookup" msgid="4517085806977851374">"URL-i ei leitud."</string>
+    <string name="httpError" msgid="7956392511146698522">"Ilmnes võrgu viga."</string>
+    <string name="httpErrorLookup" msgid="4711687456111963163">"URL-i ei leita."</string>
     <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Saidi autentimise skeemi ei toetata."</string>
-    <string name="httpErrorAuth" msgid="7293960746955020542">"Autentimine ebaõnnestus."</string>
+    <string name="httpErrorAuth" msgid="1435065629438044534">"Autentimine ebaõnnestus."</string>
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Puhverserveri kaudu autentimine ebaõnnestus."</string>
-    <string name="httpErrorConnect" msgid="7623096283505770433">"Ühendus serveriga ebaõnnestus."</string>
-    <string name="httpErrorIO" msgid="4270874999047767599">"Serveril ei õnnestunud sidet luua. Proovige hiljem uuesti."</string>
+    <string name="httpErrorConnect" msgid="8714273236364640549">"Serveriga ei saanud ühendust."</string>
+    <string name="httpErrorIO" msgid="2340558197489302188">"Serveriga ei saanud ühendust. Proovige hiljem uuesti."</string>
     <string name="httpErrorTimeout" msgid="4743403703762883954">"Ühendus serveriga aegunud."</string>
     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Leht sisaldab liiga palju serveri ümbersuunamisi."</string>
     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protokolli ei toetata."</string>
-    <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Turvalist ühendust ei saanud luua."</string>
-    <string name="httpErrorBadUrl" msgid="6088183159988619736">"Lehte ei saa avada, kuna URL on vale."</string>
-    <string name="httpErrorFile" msgid="8250549644091165175">"Faili ei saa avada."</string>
-    <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Nõutud faili ei leitud."</string>
+    <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Turvalist ühendust ei saanud luua."</string>
+    <string name="httpErrorBadUrl" msgid="3636929722728881972">"Lehte pole võimalik avada, kuna URL on vale."</string>
+    <string name="httpErrorFile" msgid="2170788515052558676">"Failile ei pääse juurde."</string>
+    <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Soovitud faili ei leitud."</string>
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Töötlemisel on liiga palju taotlusi. Proovige hiljem uuesti."</string>
-    <string name="notification_title" msgid="1259940370369187045">"Viga kontole <xliff:g id="ACCOUNT">%1$s</xliff:g> sisselogimisel"</string>
+    <string name="notification_title" msgid="8967710025036163822">"Viga kontole <xliff:g id="ACCOUNT">%1$s</xliff:g> sisselogimisel"</string>
     <string name="contentServiceSync" msgid="8353523060269335667">"Sünkroonimine"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sünkroonimine"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liiga palju üksuse <xliff:g id="CONTENT_TYPE">%s</xliff:g> kustutusi."</string>
-    <string name="low_memory" product="tablet" msgid="2292820184396262278">"Tahvelarvuti mälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
-    <string name="low_memory" product="default" msgid="6632412458436461203">"Telefonimälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
+    <string name="low_memory" product="tablet" msgid="6494019234102154896">"Tahvelarvuti mäluruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
+    <string name="low_memory" product="default" msgid="3475999286680000541">"Telefonimälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
     <string name="me" msgid="6545696007631404292">"Mina"</string>
     <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tahvelarvuti valikud"</string>
     <string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonivalikud"</string>
@@ -137,6 +137,9 @@
     <string name="turn_off_radio" msgid="8198784949987062346">"Lülitage raadioside välja"</string>
     <string name="screen_lock" msgid="799094655496098153">"Ekraanilukk"</string>
     <string name="power_off" msgid="4266614107412865048">"Lülita välja"</string>
+    <string name="silent_mode_silent" msgid="319298163018473078">"Helin on väljas"</string>
+    <string name="silent_mode_vibrate" msgid="7072043388581551395">"Vibreeriv helin"</string>
+    <string name="silent_mode_ring" msgid="8592241816194074353">"Helin on sees"</string>
     <string name="shutdown_progress" msgid="2281079257329981203">"Väljalülitamine ..."</string>
     <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Teie tahvelarvuti lülitub välja."</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Teie telefon lülitub välja."</string>
@@ -157,16 +160,16 @@
     <string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tasulised teenused"</string>
-    <string name="permgroupdesc_costMoney" msgid="8596717365335027057">"Võimaldab rakendustel teha tasulisi toiminguid."</string>
+    <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Tasuliste toimingute tegemine."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Teie sõnumid"</string>
     <string name="permgroupdesc_messages" msgid="7821999071003699236">"Teie SMS-, meili- ja muude sõnumite lugemine ja kirjutamine."</string>
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Teie isiklikud andmed"</string>
     <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Otsene juurdepääs tahvelarvutisse salvestatud kontaktidele ja kalendrile."</string>
     <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Otsene juurdepääs telefoni salvestatud kontaktidele ja kalendrile."</string>
     <string name="permgrouplab_location" msgid="635149742436692049">"Teie asukoht"</string>
-    <string name="permgroupdesc_location" msgid="2430258821648348660">"Jälgige oma füüsilist asukohta"</string>
+    <string name="permgroupdesc_location" msgid="5704679763124170100">"Jälgige oma füüsilist asukohta."</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"Võrgusuhtlus"</string>
-    <string name="permgroupdesc_network" msgid="4917593670797570584">"Võimaldab rakendustel pääseda juurde erinevatele võrgufunktsioonidele."</string>
+    <string name="permgroupdesc_network" msgid="4478299413241861987">"Juurdepääs erinevatele võrgufunktsioonidele."</string>
     <string name="permgrouplab_accounts" msgid="3359646291125325519">"Teie kontod"</string>
     <string name="permgroupdesc_accounts" msgid="4948732641827091312">"Juurdepääs saadaolevatele kontodele."</string>
     <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Riistvara juhtelemendid"</string>
@@ -206,16 +209,18 @@
     <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Võimaldab rakendusel kirjutada teie telefoni või SIM-kaardile salvestatud SMS-sõnumitesse. Pahatahtlikud rakendused võivad teie sõnumid kustutada."</string>
     <string name="permlab_receiveWapPush" msgid="8258226427716551388">"võta WAP vastu"</string>
     <string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Võimaldab rakendusel vastu võtta ja töödelda WAP-sõnumeid. Pahatahtlikud rakendused võivad teie sõnumeid jälgida või neid kustutada teile näitamata."</string>
-    <string name="permlab_getTasks" msgid="6466095396623933906">"käitatud rakenduste toomine"</string>
+    <string name="permlab_getTasks" msgid="6466095396623933906">"Käitatud rakenduste toomine"</string>
     <string name="permdesc_getTasks" msgid="6608159250520381359">"Võimaldab rakendusel hankida teavet praegu töötavate ja hiljuti töötanud ülesannete kohta. Pahatahtlikud rakendused võivad avastada privaatset teavet teiste rakenduste kohta."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"käitatud rakenduste ümberjärjestamine"</string>
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Võimaldab rakendusel teisaldada ülesanded esiplaanile ja taustale. Pahatahtlikud rakendused võivad sundida end esiplaanile tulema teie loata."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"käitatud rakenduste peatamine"</string>
-    <string name="permdesc_removeTasks" msgid="1000226123143185094">"Võimaldab rakendusel eemaldada ülesandeid ja peatada nende rakendused. Pahatahtlikud rakendused võivad häirida teiste rakenduste käitumist."</string>
+    <string name="permdesc_removeTasks" msgid="1394714352062635493">"Võimaldab rakendusel eemaldada ülesanded ja peatada nende rakendused. Pahatahtlikud rakendused võivad häirida teiste rakenduste käitumist."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"kuva ühilduvuse seadmine"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Võimaldab rakendusel juhtida teiste rakenduste kuva ühilduvuse režiimi. Pahatahtlikud rakendused võivad teisi rakendusi häirida."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"Rakenduse silumise lubamine"</string>
-    <string name="permdesc_setDebugApp" msgid="6215654419903651172">"Võimaldab rakendusel lülitada sisse teise rakenduse silumise. Pahatahtlikud rakendused võivad seda kasutada teiste rakenduste peatamiseks."</string>
+    <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Võimaldab rakendusel lülitada sisse teise rakenduse silumise. Pahatahtlikud rakendused võivad seda kasutada teiste rakenduste peatamiseks."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuda UI-seadeid"</string>
-    <string name="permdesc_changeConfiguration" msgid="4104052649900380324">"Võimaldab rakendusel muuta praegust konfiguratsiooni, näiteks lokaati või üldist kirjasuurust."</string>
+    <string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Võimaldab rakendusel muuta praegust konfiguratsiooni, näiteks lokaati või üldist kirjasuurust."</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"autorežiimi lubamine"</string>
     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Võimaldab rakendusel autorežiimi lubada."</string>
     <string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"taustaprotsesside peatamine"</string>
@@ -251,11 +256,11 @@
     <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"täieliku varukoopia kinnitamine või toimingu taastamine"</string>
     <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Võimaldab rakendusel käivitada täieliku varukoopia kinnitusliidese. Mitte kasutada üheski rakenduses."</string>
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"kuva volituseta aknad"</string>
-    <string name="permdesc_internalSystemWindow" msgid="6510907081810231374">"Võimaldab rakendusel luua aknaid, mis on mõeldud süsteemisisesele kasutajaliidesele. Mitte kasutada tavarakenduste puhul."</string>
+    <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Võimaldab rakendusel luua aknaid, mis on mõeldud kasutamiseks süsteemisisesele kasutajaliidesele. Mitte kasutada tavarakenduste puhul."</string>
     <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"kuva süsteemitasemel märguandeid"</string>
     <string name="permdesc_systemAlertWindow" msgid="8507863469978066409">"Võimaldab rakendusel kuvada süsteemihoiatuste aknaid. Pahatahtlikud rakendused võivad hõlmata kogu ekraani."</string>
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"muuda üldist animatsioonikiirust"</string>
-    <string name="permdesc_setAnimationScale" msgid="6505093307223395456">"Võimaldab rakendusel muuta igal ajal üldist animatsiooni kiirust (animatsioone kiirendada või aeglustada)."</string>
+    <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Võimaldab rakendusel muuta animatsiooni üldist kiirust (animatsioone kiirendada või aeglustada) ükskõik millal."</string>
     <string name="permlab_manageAppTokens" msgid="1286505717050121370">"Rakenduse lubade haldamine"</string>
     <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Võimaldab rakendusel luua ja hallata tema enda lube, möödudes tavapärasest Z-järjekorrast. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_injectEvents" msgid="1378746584023586600">"vajuta klahve ja juhtnuppe"</string>
@@ -266,9 +271,9 @@
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"seo sisestusmeetodiga"</string>
     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lubab omanikul siduda sisestusmeetodi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindTextService" msgid="7358378401915287938">"tekstiteenusega sidumine"</string>
-    <string name="permdesc_bindTextService" msgid="8151968910973998670">"Võimaldab omanikul siduda tekstiteenuse (nt SpellCheckerService) ülataseme liidest. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permdesc_bindTextService" msgid="8151968910973998670">"Võimaldab omanikul siduda tekstiteenuse (nt SpellCheckerService) ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindVpnService" msgid="4708596021161473255">"seo VPN-teenusega"</string>
-    <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Võimaldab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Võimaldab omanikul siduda VPN-teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"taustapildiga sidumine"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lubab omanikul siduda taustapildi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidinateenusega sidumine"</string>
@@ -292,7 +297,7 @@
     <string name="permlab_getPackageSize" msgid="7472921768357981986">"Rakenduse mäluruumi mõõtmine"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Võimaldab rakendusel tuua oma koodi, andmed ja vahemälu suurused"</string>
     <string name="permlab_installPackages" msgid="2199128482820306924">"Rakenduste otse installimine"</string>
-    <string name="permdesc_installPackages" msgid="5628530972548071284">"Võimaldab rakendusel installida uusi või värskendatud Android-pakette. Pahatahtlikud rakendused võivad seda kasutada uute rakenduste lisamiseks omavoliliselt võimsate õigustega."</string>
+    <string name="permdesc_installPackages" msgid="5628530972548071284">"Võimaldab rakendusel installida uusi või värskendatud Android-pakette. Pahatahtlikud rakendused võivad selle abil lisada uusi meelevaldse tegevuse lubadega rakendusi."</string>
     <string name="permlab_clearAppCache" msgid="7487279391723526815">"Kõigi rakenduse vahemäluandmete kustutamine"</string>
     <string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Võimaldab rakendusel vabastada tahvelarvuti mälu, kustutades faile otse rakenduse kataloogist. Süsteem on juurdepääsu sellele harilikult väga piiranud."</string>
     <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Võimaldab rakendusel vabastada telefoni mälu, kustutades faile otse rakenduse kataloogist. Süsteem on juurdepääsu sellele harilikult väga piiranud."</string>
@@ -301,6 +306,8 @@
     <string name="permlab_readLogs" msgid="6615778543198967614">"tundlike logiandmete lugemine"</string>
     <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Võimaldab rakendusel lugeda süsteemi erinevaid logifaile. Nii on võimalik avastada üldist teavet selle kohta, mida te tahvelarvutiga teete, sh isiklikku või privaatset teavet."</string>
     <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Võimaldab rakendusel lugeda süsteemi erinevaid logifaile. Nii on võimalik avastada üldist teavet selle kohta, mida te telefoniga teete, mis võib kaasata ka isiklikku või privaatset teavet."</string>
+    <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"Mis tahes meediumidekooderi kasutamine taasesituseks"</string>
+    <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Võimaldab rakendusel taasesituseks kasutada mis tahes installitud meediumidekooderit."</string>
     <string name="permlab_diagnostic" msgid="8076743953908000342">"loe/kirjuta valija allikaid"</string>
     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Võimaldab rakendusel lugeda valimisrühma mis tahes ressurssi ja sellesse kirjutada (näiteks kaustas /dev olevad failid). See võib mõjutada süsteemi stabiilsust ja turvet. Seda tohiks kasutada tootja või operaator AINULT riistvaraspetsiifiliseks diagnostikaks."</string>
     <string name="permlab_changeComponentState" msgid="6335576775711095931">"Rakenduse komponentide lubamine või keelamine"</string>
@@ -335,7 +342,7 @@
     <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Sotsiaalvoogu kirjutamine"</string>
     <string name="permdesc_writeSocialStream" product="default" msgid="3496277176955721451">"Võimaldab rakendusel kuvada sõprade suhtlusuudiseid. Pahatahtlikud rakendused saavad selle abil teie sõpra teeselda ja meelitada teid avaldama paroole või muud konfidentsiaalset teavet."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"kalendrisündmuste lugemine ja konfidentsiaalne teave"</string>
-    <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Võimaldab rakendusel lugeda kõiki teie tahvelarvutisse salvestatud kalendrisündmusi, sh teie sõprade või töökaaslaste omi. Pahatahtlikud rakendused võivad nendest kalendritest välja võtta isiklikku teavet ilma teadmiseta."</string>
+    <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Võimaldab rakendusel lugeda kõiki teie tahvelarvutisse salvestatud kalendrisündmusi, sh teie sõprade või töökaaslaste omi. Pahatahtlikud rakendused võivad nendest kalendritest välja võtta isiklikku teavet ilma omanike teadmata."</string>
     <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Võimaldab rakendusel lugeda kõiki teie telefoni salvestatud kalendrisündmusi, sh teie sõprade või töökaaslaste omi. Pahatahtlikud rakendused võivad nendest kalendritest välja võtta isiklikku teavet omaniku teadmiseta."</string>
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"kalendrisündmuste lisamine või muutmine ja külalistele omanike teadmata meili saatmine"</string>
     <string name="permdesc_writeCalendar" msgid="2243771395254848873">"Võimaldab rakendusel saata sündmusekutseid kalendri omanikuna ning lisada, eemaldada või muuta sündmusi, mida saate oma seadmel muuta, sh oma sõprade või töökaaslaste omi. Pahatahtlikud rakendused võivad saata rämpsposti, mis näib olevat tulnud kalendriomanikelt, muuta sündmusi omanike teadmata või lisada võltssündmusi."</string>
@@ -434,7 +441,7 @@
     <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Võimaldab rakendusel muuta tahvelarvuti ajavööndit."</string>
     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Võimaldab rakendusel muuta telefoni ajavööndit."</string>
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"AccountManagerService\'ina tegutsemine"</string>
-    <string name="permdesc_accountManagerService" msgid="2684502137670299915">"Võimaldab rakendusel helistada konto autentijatele."</string>
+    <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Võimaldab rakendusel helistada konto autentijatele."</string>
     <string name="permlab_getAccounts" msgid="4549918644233460103">"leia teadaolevad kontod"</string>
     <string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Võimaldab rakendusel hankida tahvelarvutile teadaolevate kontode loendi."</string>
     <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Võimaldab rakendusel saada telefonile teadaolevate kontode loendi."</string>
@@ -465,6 +472,10 @@
     <string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"Bluetoothi haldamine"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Võimaldab rakendusel seadistada kohalikku Bluetooth-tahvelarvutit ning leida ja siduda seda kaugseadmetega."</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Võimaldab rakendusel seadistada kohalikku Bluetooth-telefoni ning leida ja siduda seda kaugseadmetega."</string>
+    <string name="permlab_accessWimaxState" msgid="1232061307208861588">"WiMAX-i oleku kuvamine"</string>
+    <string name="permdesc_accessWimaxState" msgid="5914958077555177749">"Võimaldab rakendusel vaadata WiMAX-i olekuteavet."</string>
+    <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-i oleku muutmine"</string>
+    <string name="permdesc_changeWimaxState" msgid="3328853825006455912">"Võimaldab rakendusel luua ja katkestada ühenduse WiMAX-i võrguga."</string>
     <string name="permlab_bluetooth" msgid="8361038707857018732">"loo Bluetooth-ühendusi"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Võimaldab rakendusel vaadata kohaliku Bluetooth-tahvelarvuti konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
     <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Võimaldab rakendusel vaadata kohaliku Bluetooth-telefoni konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
@@ -501,27 +512,27 @@
     <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"võrgueeskirjade haldamine"</string>
     <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Võimaldab rakendusel hallata võrgueeskirju ja määratleda rakendusespetsiifilisi reegleid."</string>
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"võrgukasutuse arvestamise muutmine"</string>
-    <string name="permdesc_modifyNetworkAccounting" msgid="8553240749784321765">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
+    <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
-    <string name="policydesc_limitPassword" msgid="9083400080861728056">"Ekraaniluku paroolide lubatud pikkuse ja tähemärkide kontrollimine"</string>
+    <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Jälgib ekraani avamisel valesti sisestatud paroolide arvu ja lukustab tahvelarvuti või kustutab kõik selle andmed, kui vale parool sisestatakse liiga palju kordi."</string>
     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Jälgib ekraani avamisel valesti sisestatud paroolide arvu ja lukustab telefoni või kustutab kõik selle andmed, kui vale parool sisestatakse liiga palju kordi."</string>
     <string name="policylab_resetPassword" msgid="2620077191242688955">"Ekraaniluku parooli muutmine"</string>
-    <string name="policydesc_resetPassword" msgid="5391240616981297361">"Ekraaniluku parooli muutmine"</string>
+    <string name="policydesc_resetPassword" msgid="605963962301904458">"Ekraaniluku parooli muutmine."</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Ekraani lukustamine"</string>
-    <string name="policydesc_forceLock" msgid="5696964126226028442">"Juhtige, kuidas ja millal ekraan lukustub"</string>
+    <string name="policydesc_forceLock" msgid="1141797588403827138">"Määrake, kuidas ja millal ekraan lukustub."</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Kõikide andmete kustutamine"</string>
-    <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Tahvelarvuti andmete hoiatuseta kustutamine, lähtestades tehaseandmed"</string>
-    <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Telefoniandmete hoiatuseta kustutamine, lähtestades tehaseandmed"</string>
+    <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Kustutage tahvelarvuti andmed hoiatamata, lähtestades arvuti tehaseandmetele."</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Kustuta telefoniandmed hoiatuseta, lähtestades telefoni tehaseandmetele."</string>
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Määra seadme globaalne puhverserver"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Eeskirjade lubamise ajal kasutatava seadme globaalse puhverserveri määramine. Ainult esimese seadme administraator määrab tõhusa globaalse puhverserveri."</string>
     <string name="policylab_expirePassword" msgid="885279151847254056">"Ekraaniluku parooli aegumise määramine"</string>
-    <string name="policydesc_expirePassword" msgid="4844430354224822074">"Juhib, kui sageli ekraaniluku parooli tuleb muuta"</string>
+    <string name="policydesc_expirePassword" msgid="1729725226314691591">"Määrake ekraaniluku parooli muutmissagedus."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Salvestamise krüpt. määramine"</string>
-    <string name="policydesc_encryptedStorage" msgid="8877192718681120469">"Nõue, et salvestatud rakenduse andmed krüpteeritakse"</string>
+    <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Nõua salvestatud rakenduse andmete krüpteerimist."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Keela kaamerad"</string>
-    <string name="policydesc_disableCamera" msgid="5680054212889413366">"Väldi kõigi seadme kaamerate kasutamist"</string>
+    <string name="policydesc_disableCamera" msgid="2306349042834754597">"Vältige seadme kõigi kaamerate kasutamist."</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Kodu"</item>
     <item msgid="869923650527136615">"Mobiil"</item>
@@ -642,7 +653,7 @@
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Puudutage parooli sisestamiseks"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Avamiseks sisestage parool"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Avamiseks sisestage PIN-kood"</string>
-    <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Vale PIN-kood."</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Vale PIN-kood."</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"Avamiseks vajutage menüüklahvi, seejärel klahvi 0."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Hädaabinumber"</string>
     <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Teenus puudub."</string>
@@ -655,6 +666,7 @@
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Õige."</string>
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Proovige uuesti"</string>
     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Proovige uuesti"</string>
+    <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimaalne teenusega Face Unlock avamise katsete arv on ületatud"</string>
     <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Laadimine, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_charged" msgid="4938930459620989972">"Laetud."</string>
     <string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
@@ -688,14 +700,14 @@
     <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Proovige uuesti <xliff:g id="NUMBER">%d</xliff:g> sekundi pärast."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Kas unustasite mustri?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Konto avamine"</string>
-    <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Liiga palju mustrikatseid."</string>
-    <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Avamiseks logige sisse oma Google\'i kontoga"</string>
+    <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Liiga palju mustrikatseid"</string>
+    <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Avamiseks logige sisse oma Google\'i kontoga."</string>
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Kasutajanimi (e-post)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parool"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Logi sisse"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Vale kasutajanimi või parool."</string>
-    <string name="lockscreen_glogin_account_recovery_hint" msgid="8253152905532900548">"Kas unustasite oma kasutajanime või parooli?"\n"Külastage aadressi "<b>"google.com/accounts/recovery"</b></string>
-    <string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Kontrollimine ..."</string>
+    <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Kas unustasite oma kasutajanime või parooli?"\n"Külastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Kontrollimine ..."</string>
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Ava"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Heli sisse"</string>
     <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Heli välja"</string>
@@ -712,13 +724,13 @@
     <string name="factorytest_not_system" msgid="4435201656767276723">"Toimingut FACTORY_TEST toetatakse ainult kausta \\system\\app installitud pakettide puhul."</string>
     <string name="factorytest_no_action" msgid="872991874799998561">"Ei leitud ühtegi paketti, mis võimaldaks toimingut FACTORY_TEST."</string>
     <string name="factorytest_reboot" msgid="6320168203050791643">"Taaskäivita"</string>
-    <string name="js_dialog_title" msgid="8143918455087008109">"Veebileht aadressil <xliff:g id="TITLE">%s</xliff:g> ütleb:"</string>
+    <string name="js_dialog_title" msgid="1987483977834603872">"Leht  „<xliff:g id="TITLE">%s</xliff:g>” ütleb järgmist."</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload" msgid="730366588032430474">"Kas soovite sellelt lehelt lahkuda?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Jätkamiseks puudutage OK, praegusele lehele jäämiseks valikut Tühista."</string>
+    <string name="js_dialog_before_unload" msgid="730366588032430474">"Kas soovite sellelt lehelt lahkuda?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Jätkamiseks puudutage valikut OK, praegusele lehele jäämiseks valikut Tühista."</string>
     <string name="save_password_label" msgid="6860261758665825069">"Kinnita"</string>
-    <string name="double_tap_toast" msgid="2729045387923870404">"Vihje: suurendamiseks ja vähendamiseks puudutage kaks korda."</string>
-    <string name="autofill_this_form" msgid="1272247532604569872">"Autom."</string>
-    <string name="setup_autofill" msgid="8154593408885654044">"Aut. täit. sead."</string>
+    <string name="double_tap_toast" msgid="4595046515400268881">"Vihje: suurendamiseks ja vähendamiseks puudutage kaks korda."</string>
+    <string name="autofill_this_form" msgid="4616758841157816676">"Automaatne täitmine"</string>
+    <string name="setup_autofill" msgid="7103495070180590814">"Automaatse täitmise seadistamine"</string>
     <string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
     <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
     <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -750,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Võimaldab rakendusel kinnitada, et paketti saab installida."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sidumine paketi kinnitajaga"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lubab omanikul teha taotlusi paketi kinnitajate kohta. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"juurdepääs jadaportidele"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Võimaldab omanikul SerialManageri API-liidese abil jadaportidele juurde pääseda."</string>
     <string name="save_password_message" msgid="767344687139195790">"Kas soovite, et brauser jätaks selle parooli meelde?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Mitte praegu"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Pidage meeles"</string>
@@ -853,9 +867,9 @@
     <string name="weeks" msgid="6509623834583944518">"nädalat"</string>
     <string name="year" msgid="4001118221013892076">"aasta"</string>
     <string name="years" msgid="6881577717993213522">"aastat"</string>
-    <string name="VideoView_error_title" msgid="5927895235831021723">"Videot ei saa esitada"</string>
+    <string name="VideoView_error_title" msgid="3534509135438353077">"Probleem videoga"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"See video ei sobi voogesituseks selles seadmes."</string>
-    <string name="VideoView_error_text_unknown" msgid="4309847331399592194">"Seda videot ei saa esitada."</string>
+    <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videot ei saa esitada."</string>
     <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
     <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="noon" msgid="7245353528818587908">"keskpäev"</string>
@@ -891,7 +905,7 @@
     <string name="whichApplication" msgid="4533185947064773386">"Lõpetage toiming rakendusega"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Kasuta vaikimisi selleks toiminguks."</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Tühjendage vaikeandmed valikutes Süsteemiseaded &gt; Rakendused &gt; Allalaaditud."</string>
-    <string name="chooseActivity" msgid="1009246475582238425">"Valige toiming"</string>
+    <string name="chooseActivity" msgid="7486876147751803333">"Toimingu valimine"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"USB-seadme jaoks rakenduse valimine"</string>
     <string name="noApplications" msgid="2991814273936504689">"Ükski rakendus ei saa seda toimingut teostada."</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
@@ -905,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Teata"</string>
     <string name="wait" msgid="7147118217226317732">"Oodake"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Leht ei reageeri."\n\n"Kas soovite selle sulgeda?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Rakendus on ümber suunatud"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> on nüüd käivitunud."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Algselt käivitati rakendus <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -925,11 +940,11 @@
     <string name="old_app_description" msgid="2082094275580358049">"Ärge käivitage uut rakendust."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Käivitage rakendus <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Peatage vana rakendus salvestamata."</string>
-    <string name="sendText" msgid="5132506121645618310">"Valige teksti jaoks toiming"</string>
+    <string name="sendText" msgid="5209874571959469142">"Valige teksti jaoks toiming"</string>
     <string name="volume_ringtone" msgid="6885421406845734650">"Helina helitugevus"</string>
     <string name="volume_music" msgid="5421651157138628171">"Meediumi helitugevus"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Esitatakse Bluetoothi kaudu"</string>
-    <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Valitud on hääletu helin"</string>
+    <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Valitud on hääletu märguanne"</string>
     <string name="volume_call" msgid="3941680041282788711">"Kõne helitugevus"</string>
     <string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetoothi kõne helitugevus"</string>
     <string name="volume_alarm" msgid="1985191616042689100">"Alarmi helitugevus"</string>
@@ -953,17 +968,22 @@
     <item quantity="one" msgid="1634101450343277345">"Avatud WiFi võrk on saadaval"</item>
     <item quantity="other" msgid="7915895323644292768">"Avatud WiFi-võrgud on saadaval"</item>
   </plurals>
-    <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logi sisse WiFi-võrku"</string>
+    <string name="wifi_available_sign_in" msgid="4029489716605255386">"Logige sisse WiFi-võrku"</string>
     <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) -->
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" on halb Interneti-ühendus."</string>
+    <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" on halb Interneti-ühendus."</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2804722042556269129">"Käivitage WiFi Directi töö. See lülitab WiFi-kliendi/-tööpunkti töö välja."</string>
-    <string name="wifi_p2p_failed_message" msgid="1820097493844848281">"Otsese WiFi-ühenduse käivitamine ebaõnnestus"</string>
-    <string name="wifi_p2p_pbc_go_negotiation_request_message" msgid="3170321684621420428">"WiFi Directi ühenduse seadistamise taotlus seadmelt <xliff:g id="P2P_DEVICE_ADDRESS">%1$s</xliff:g>. Nõustumiseks klõpsake OK."</string>
-    <string name="wifi_p2p_pin_go_negotiation_request_message" msgid="5177412094633377308">"WiFi Directi ühenduse seadistuse taotlus seadmelt <xliff:g id="P2P_DEVICE_ADDRESS">%1$s</xliff:g>. Jätkamiseks sisestage PIN-kood."</string>
-    <string name="wifi_p2p_pin_display_message" msgid="2834049169114922902">"Jätkamiseks tuleb ühenduse seadistamise eesmärgil sisestada partnerseadmesse <xliff:g id="P2P_CLIENT_ADDRESS">%2$s</xliff:g> WPS-i PIN-kood <xliff:g id="P2P_WPS_PIN">%1$s</xliff:g>."</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käivitage WiFi otseühendus. See lülitab välja WiFi kliendi/leviala."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"WiFi otseühenduse käivitamine ebaõnnestus."</string>
+    <string name="accept" msgid="1645267259272829559">"Nõustu"</string>
+    <string name="decline" msgid="2112225451706137894">"Keeldu"</string>
+    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutse on saadetud"</string>
+    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Kutse ühendamiseks"</string>
+    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Saatja:"</string>
+    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Saaja:"</string>
+    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Sisestage nõutav PIN-kood:"</string>
+    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kood:"</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"WiFi Direct on sees"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Puuted seadete jaoks"</string>
     <string name="select_character" msgid="3365550120617701745">"Sisesta tähemärk"</string>
@@ -976,7 +996,7 @@
     <string name="sim_removed_message" msgid="2333164559970958645">"Mobiilsidevõrk ei ole saadaval, kuni sisestate kehtiva SIM-kaardi ja taaskäivitate seadme."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Valmis"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"SIM-kaart lisatud"</string>
-    <string name="sim_added_message" msgid="1209265974048554242">"Mobiilsidevõrku pääsemiseks peate oma seadme taaskäivitama."</string>
+    <string name="sim_added_message" msgid="6599945301141050216">"Mobiilsidevõrku pääsemiseks taaskäivitage seade."</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"Taaskäivita"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"Kellaaja määramine"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"Kuupäeva määramine"</string>
@@ -985,31 +1005,31 @@
     <string name="no_permissions" msgid="7283357728219338112">"Lube pole vaja"</string>
     <string name="perms_hide" msgid="7283915391320676226"><b>"Peida"</b></string>
     <string name="perms_show_all" msgid="2671791163933091180"><b>"Näita kõiki"</b></string>
-    <string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-massmälu"</string>
+    <string name="usb_storage_activity_title" msgid="4465055157209648641">"USB-massmälu"</string>
     <string name="usb_storage_title" msgid="5901459041398751495">"USB ühendatud"</string>
-    <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Olete arvutiga USB kaudu ühendatud. Puudutage allolevat nuppu, kui soovite faile arvuti ja Androidi USB-mäluseadme vahel kopeerida."</string>
-    <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Olete arvutiga USB kaudu ühendatud. Puudutage allolevat nuppu, kui soovite faile arvuti ja Androidi SD-kaardi vahel kopeerida."</string>
+    <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Teil on arvutiga ühendus USB kaudu. Puudutage allolevat nuppu, kui soovite faile arvuti ja Androidi USB-salvestusruumi vahel kopeerida."</string>
+    <string name="usb_storage_message" product="default" msgid="805351000446037811">"Olete arvutiga ühendatud USB kaudu. Puudutage allolevat nuppu, kui soovite faile arvuti ja Androidi SD-kaardi vahel kopeerida."</string>
     <string name="usb_storage_button_mount" msgid="1052259930369508235">"Lülita USB-mäluseade sisse"</string>
-    <string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Probleem USB-mäluseadme kasutamisel USB-mäluseadmena."</string>
-    <string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Probleem SD-kaardi kasutamisel USB-mäluseadmena."</string>
+    <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"Probleem USB-salvestusruumi kasutamisel USB-mäluseadmena."</string>
+    <string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"Probleem SD-kaardi kasutamisel USB-mäluseadmena."</string>
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB ühendatud"</string>
-    <string name="usb_storage_notification_message" msgid="7380082404288219341">"Valige failide kopeerimiseks arvutist/arvutisse."</string>
+    <string name="usb_storage_notification_message" msgid="939822783828183763">"Puudutage, et kopeerida faile arvutist/arvutisse."</string>
     <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Lülita USB-mäluseade välja"</string>
-    <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Valige USB-mäluseadme väljalülitamiseks."</string>
+    <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"USB-salvestusruumi väljalülitamiseks puudutage."</string>
     <string name="usb_storage_stop_title" msgid="660129851708775853">"USB kasutusel"</string>
-    <string name="usb_storage_stop_message" product="nosdcard" msgid="1368842269463745067">"Enne USB-mäluseadme väljalülitamist veenduge, et olete oma Androidi USB-mäluseadme arvutist eemaldanud (väljutanud)."</string>
-    <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Enne USB-seadme väljalülitamist veenduge, et olete oma Androidi SD-kaardi arvutist eemaldanud (“väljutanud“)."</string>
+    <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"Enne USB-salvestusruumi väljalülitamist eraldage (väljutage) Androidi USB-salvestusruum arvutist."</string>
+    <string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"Enne USB-salvestusruumi väljalülitamist eemaldage (väljutage) Androidi SD-kaart arvutist."</string>
     <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Lülita USB-mäluseade välja"</string>
-    <string name="usb_storage_stop_error_message" msgid="143881914840412108">"USB-mäluseadme väljalülitamisel ilmnes probleem. Veenduge, et olete USB-hosti eemaldanud ja proovige siis uuesti."</string>
+    <string name="usb_storage_stop_error_message" msgid="1970374898263063836">"Tekkis probleem USB-salvestusruumi väljalülitamisega. Kontrollige, kas olete USB-hosti eemaldanud, ja proovige seejärel uuesti."</string>
     <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Lülita USB-mäluseade sisse"</string>
-    <string name="dlg_confirm_kill_storage_users_text" msgid="6206212680430268343">"USB-seadme sisselülitamisel peatuvad mõned teie kasutatavad rakendused ja on võimalik, et neid ei saa kasutada seni, kuni USB-seadme välja lülitate."</string>
+    <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Kui lülitate USB-salvestusruumi sisse, võivad mõned kasutatavad rakendused peatuda ega pruugi olla saadaval enne USB-salvestusruumi väljalülitamist."</string>
     <string name="dlg_error_title" msgid="7323658469626514207">"USB toiming ebaõnnestus"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ühendatud meediumiseadmena"</string>
     <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Ühendatud kaamerana"</string>
     <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Ühendatud installijana"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ühendatud USB-lisaseadmega"</string>
-    <string name="usb_notification_message" msgid="4447869605109736382">"Puudutage teiste USB-valikute kuvamiseks"</string>
+    <string name="usb_notification_message" msgid="2290859399983720271">"Puudutage teisi USB valikuid."</string>
     <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Vormind. USB-seade?"</string>
     <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Kas vormindada SD-kaart?"</string>
     <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Kõik USB-mäluseadmele salvestatud failid kustutatakse. Seda toimingut ei saa tagasi võtta."</string>
@@ -1027,12 +1047,12 @@
     <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Vigade kontrollimine."</string>
     <string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"Tühi USB-mäluseade"</string>
     <string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"Tühi SD-kaart"</string>
-    <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"USB-mäluseade on tühi või toetuseta failisüsteemiga."</string>
-    <string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"SD-kaart on tühi või toetuseta failisüsteemiga."</string>
+    <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="7840121067427269500">"USB-salvestusruum on tühi või ei toeta failisüsteemi."</string>
+    <string name="ext_media_nofs_notification_message" product="default" msgid="8641065641786923604">"SD-kaart on tühi või ei toetata selle failisüsteemi."</string>
     <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Kahjustatud USB-mäluseade"</string>
     <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Kahjustatud SD-kaart"</string>
-    <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB-mäluseade on kahjustatud. Võib-olla peate selle uuesti vormindama."</string>
-    <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"SD-kaart on kahjustatud. Võib-olla peale selle uuesti vormindama."</string>
+    <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="1795917578395333280">"USB-salvestusruum on kahjustatud. Proovige uuesti vormindada."</string>
+    <string name="ext_media_unmountable_notification_message" product="default" msgid="1753898567525568253">"SD-kaart on kahjustatud. Proovige uuesti vormindada."</string>
     <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-seade eemaldati ootamatult"</string>
     <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"SD-kaart on ootamatult eemaldatud"</string>
     <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Andmekao vältimiseks lahutage USB-mäluseade enne eemaldamist."</string>
@@ -1045,13 +1065,13 @@
     <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Eemaldatud SD-kaart"</string>
     <string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"USB-mäluseade eemaldatud. Sisestage uus meedium."</string>
     <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD-kaart on eemaldatud. Sisestage uus."</string>
-    <string name="activity_list_empty" msgid="4168820609403385789">"Sobivat tegevust ei leitud"</string>
+    <string name="activity_list_empty" msgid="1675388330786841066">"Sobivat tegevust ei leitud"</string>
     <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"värskenda komponentide kasutusstatistikat"</string>
     <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Võimaldab rakendusel muuta komponendi kohta kogutud kasutusstatistikat. Mitte kasutada tavarakenduste puhul."</string>
     <string name="permlab_copyProtectedData" msgid="4341036311211406692">"Sisu kopeerimine"</string>
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Võimaldab rakendusel võtta sisu kopeerimiseks appi vaikekonteinerteenuse. Mitte kasutada tavarakenduste puhul."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Suumi juhtimiseks puudutage kaks korda"</string>
-    <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Viga vidina täitmisel"</string>
+    <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidinat ei saanud lisada."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Mine"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Otsing"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"Saada"</string>
@@ -1063,35 +1083,35 @@
     <string name="create_contact_using" msgid="4947405226788104538">"Loo kontakt"\n"numbriga <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Üks või mitu rakendust taotlevad luba pääseda nüüd ja edaspidi teie kontole juurde."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Kas soovite taotluse lubada?"</string>
-    <string name="grant_permissions_header_text" msgid="2722567482180797717">"Juurdepääsutaotlus"</string>
+    <string name="grant_permissions_header_text" msgid="6874497408201826708">"Juurdepääsutaotlus"</string>
     <string name="allow" msgid="7225948811296386551">"Luba"</string>
     <string name="deny" msgid="2081879885755434506">"Keela"</string>
-    <string name="permission_request_notification_title" msgid="5390555465778213840">"Luba taotletud"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Luba taotletud"\n"kontole <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <string name="permission_request_notification_title" msgid="6486759795926237907">"Taotletud luba"</string>
+    <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Luba on taotletud"\n"kontole <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"Sisestusmeetod"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sünkroonimine"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Juurdepääsetavus"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustapilt"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Muutke taustapilti"</string>
-    <string name="vpn_title" msgid="8219003246858087489">"VPN on aktiveeritud."</string>
+    <string name="vpn_title" msgid="19615213552042827">"VPN on aktiveeritud"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
-    <string name="vpn_text" msgid="1610714069627824309">"Koputage võrgu haldamiseks."</string>
-    <string name="vpn_text_long" msgid="4907843483284977618">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Koputage võrgu haldamiseks"</string>
+    <string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
+    <string name="vpn_text_long" msgid="6407351006249174473">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Võrgu haldamiseks puudutage."</string>
     <string name="upload_file" msgid="2897957172366730416">"Valige fail"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string>
     <string name="reset" msgid="2448168080964209908">"Lähtesta"</string>
     <string name="submit" msgid="1602335572089911941">"Saada"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Autorežiim lubatud"</string>
-    <string name="car_mode_disable_notification_message" msgid="668663626721675614">"Valige autorežiimist väljumiseks."</string>
+    <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Autorežiimist väljumiseks puudutage."</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"Jagamine või tööpunkt on aktiivne"</string>
-    <string name="tethered_notification_message" msgid="3067108323903048927">"Puudutage seadistamiseks"</string>
+    <string name="tethered_notification_message" msgid="6857031760103062982">"Seadistamiseks puudutage."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Tagasi"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Järgmine"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Jäta vahele"</string>
     <string name="throttle_warning_notification_title" msgid="4890894267454867276">"Kõrge mobiilse andmeside kasutus"</string>
-    <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Puudutage, et saada lisateavet mobiilse andmeside kasutamise kohta"</string>
+    <string name="throttle_warning_notification_message" msgid="3340822228599337743">"Mobiilse andmeside kasutamise kohta lisateabe saamiseks puudutage."</string>
     <string name="throttled_notification_title" msgid="6269541897729781332">"Mobiili andmemahupiirang ületatud"</string>
-    <string name="throttled_notification_message" msgid="4712369856601275146">"Puudutage, et saada lisateavet mobiilse andmeside kasutamise kohta"</string>
+    <string name="throttled_notification_message" msgid="5443457321354907181">"Mobiilse andmeside kasutamise kohta lisateabe saamiseks puudutage."</string>
     <string name="no_matches" msgid="8129421908915840737">"Vasted puuduvad"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Otsige lehelt"</string>
   <plurals name="matches_found">
@@ -1099,10 +1119,10 @@
     <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g>"</item>
   </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Valmis"</string>
-    <string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"USB-mäluseadme lahutamine ..."</string>
-    <string name="progress_unmounting" product="default" msgid="5556813978958789471">"SD-kaardi lahutamine ..."</string>
-    <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"USB-mäluseadme kustutamine ..."</string>
-    <string name="progress_erasing" product="default" msgid="2115214724367534095">"SD-kaardi kustutamine ..."</string>
+    <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB-salvestusruumi eemaldamine ..."</string>
+    <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD-kaardi eemaldamine ..."</string>
+    <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"USB-salvestusruumi kustutamine ..."</string>
+    <string name="progress_erasing" product="default" msgid="6596988875507043042">"SD-kaardi kustutamine ..."</string>
     <string name="format_error" product="nosdcard" msgid="6299769563624776948">"USB-mäluseadme tühjendamine ebaõnnestus."</string>
     <string name="format_error" product="default" msgid="7315248696644510935">"SD-kaardi kustutamine ebaõnnestus."</string>
     <string name="media_bad_removal" msgid="7960864061016603281">"SD-kaart eemaldati enne lahutamist."</string>
@@ -1121,17 +1141,17 @@
     <string name="gpsVerifYes" msgid="2346566072867213563">"Jah"</string>
     <string name="gpsVerifNo" msgid="1146564937346454865">"Ei"</string>
     <string name="sync_too_many_deletes" msgid="5296321850662746890">"Kustutamiste piirarv on ületatud"</string>
-    <string name="sync_too_many_deletes_desc" msgid="7030265992955132593">"Sünkroonimise tüübi <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g> konto <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> kohta on <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> kustutatud üksust. Mida te teha sooviksite?"</string>
-    <string name="sync_really_delete" msgid="8933566316059338692">"Kustuta üksused."</string>
-    <string name="sync_undo_deletes" msgid="8610996708225006328">"Kustutamiste tagasivõtmine"</string>
-    <string name="sync_do_nothing" msgid="8717589462945226869">"Ära tee praegu midagi."</string>
+    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Kustutatavad üksused kontol <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> sünkroonimistüübi <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g> jaoks: <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>. Mida soovite teha?"</string>
+    <string name="sync_really_delete" msgid="2572600103122596243">"Kustuta üksused"</string>
+    <string name="sync_undo_deletes" msgid="2941317360600338602">"Võtke kustutamised tagasi"</string>
+    <string name="sync_do_nothing" msgid="3743764740430821845">"Ära tee praegu midagi"</string>
     <string name="choose_account_label" msgid="5655203089746423927">"Konto valimine"</string>
     <string name="add_account_label" msgid="2935267344849993553">"Konto lisamine"</string>
-    <string name="choose_account_text" msgid="6891230675141555481">"Millist kontot sooviksite kasutada?"</string>
+    <string name="choose_account_text" msgid="6303348737197849675">"Millist kontot soovite kasutada?"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"Lisa konto"</string>
     <string name="number_picker_increment_button" msgid="4830170763103463443">"Suurenda"</string>
     <string name="number_picker_decrement_button" msgid="2576606679160067262">"Vähenda"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="1343063395404990189">"<xliff:g id="VALUE">%s</xliff:g> – puudutage ja hoidke all."</string>
+    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> puudutage ja hoidke."</string>
     <string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Suurendamiseks lohistage üles, vähendamiseks alla."</string>
     <string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Minutite arvu suurendamine"</string>
     <string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Minutite arvu vähendamine"</string>
@@ -1173,29 +1193,29 @@
     <string name="description_target_silent" msgid="893551287746522182">"Hääletu"</string>
     <string name="description_target_soundon" msgid="30052466675500172">"Heli on sees"</string>
     <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Avamiseks tõmmake sõrmega."</string>
-    <string name="keyboard_headset_required_to_hear_password" msgid="5913502399391940888">"Ühendage peakomplekt, et kuulata paroole."</string>
+    <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Paroolide kuulamiseks ühendage peakomplekt."</string>
     <string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punkt."</string>
     <string name="action_bar_home_description" msgid="5293600496601490216">"Liigu avalehele"</string>
     <string name="action_bar_up_description" msgid="2237496562952152589">"Liigu üles"</string>
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Rohkem valikuid"</string>
-    <string name="storage_internal" msgid="7556050805474115618">"Sisemälu"</string>
-    <string name="storage_sd_card" msgid="8921771478629812343">"SD-kaart"</string>
+    <string name="storage_internal" msgid="4891916833657929263">"Sisemine salvestusruum"</string>
+    <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
     <string name="storage_usb" msgid="3017954059538517278">"USB-mäluseade"</string>
-    <string name="extract_edit_menu_button" msgid="302060189057163906">"Muuda ..."</string>
+    <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muuda"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Andmete kasutamise hoiatus"</string>
-    <string name="data_usage_warning_body" msgid="7217480745540055170">"Kas./sätete vaatamiseks puud.-ge"</string>
+    <string name="data_usage_warning_body" msgid="2814673551471969954">"Kasutuse/sätete vaat. puudutage."</string>
     <string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G–3G-andmeside on keelatud"</string>
     <string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G-andmeside on keelatud"</string>
     <string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Mobiilne andmeside on keelatud"</string>
     <string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"WiFi-andmed on keelatud"</string>
-    <string name="data_usage_limit_body" msgid="4313857592916426843">"Puudutage lubamiseks"</string>
+    <string name="data_usage_limit_body" msgid="3317964706973601386">"Lubamiseks puudutage."</string>
     <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G andmemahupiirang ületatud"</string>
     <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G andmemahupiirang ületatud"</string>
     <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Mobiilne andmemahupiirang ületatud"</string>
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"WiFi-andmete piir on ületatud"</string>
-    <string name="data_usage_limit_snoozed_body" msgid="2932736326652880660">"<xliff:g id="SIZE">%s</xliff:g> üle kindlaksmääratud piirmäära"</string>
+    <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> üle määratud piirmäära."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Taustandmed on piiratud"</string>
-    <string name="data_usage_restricted_body" msgid="5087354814839059798">"Puudutage piirangu eemaldamiseks"</string>
+    <string name="data_usage_restricted_body" msgid="6741521330997452990">"Piirangu eemaldamiseks puudut."</string>
     <string name="ssl_certificate" msgid="6510040486049237639">"Turvasertifikaat"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"See sertifikaat on kehtiv."</string>
     <string name="issued_to" msgid="454239480274921032">"Väljastatud subjektile:"</string>
@@ -1212,7 +1232,10 @@
     <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 sõrmejälg:"</string>
     <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Kuva kõik"</string>
     <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Tegevuse valimine"</string>
-    <string name="share_action_provider_share_with" msgid="5247684435979149216">"Jagamine kasutajaga"</string>
+    <string name="share_action_provider_share_with" msgid="5247684435979149216">"Jagamine rakendusega:"</string>
     <string name="status_bar_device_locked" msgid="3092703448690669768">"Seade lukustatud."</string>
     <string name="list_delimeter" msgid="3975117572185494152">", "</string>
+    <string name="sending" msgid="3245653681008218030">"Saatmine ..."</string>
+    <string name="launchBrowserDefault" msgid="2057951947297614725">"Kas käivitada brauser?"</string>
+    <string name="SetupCallDefault" msgid="5834948469253758575">"Kas vastata kõnele?"</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e2448f9..fd7a771 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"به برنامه اجازه می‎دهد تا کارها را به پیش زمینه و پس زمینه منتقل کند. برنامه‎های مخرب می‎توانند بدون کنترل به اجبار خود را به جلو منتقل کنند."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"متوقف کردن برنامه‎های در حال اجرا"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"به برنامه اجازه می‎دهد تا کارها را حذف کند و برنامه‎های آنها را متوقف کند. برنامه‎های مخرب می‌توانند در اجرای برنامه‎های دیگر اختلال ایجاد ‎کنند."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تنظیم سازگاری با صفحه نمایش"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"به برنامه کاربردی اجازه کنترل حالت سازگاری صفحه نمایش برای برنامه‌های دیگر را می‌دهد. برنامه‌های خرابکار ممکن است باعث کارکرد نادرست دیگر برنامه‌ها شوند."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"فعال کردن عیب‌یابی برنامه"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"به برنامه اجازه می‎دهد تا عیب‌یابی را برای برنامه‌ای دیگر فعال کند. برنامه‎های مخرب می‎توانند از آن استفاده کنند تا اجرای برنامه‎های دیگر را متوقف کنند."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغییر تنظیمات UI"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"به برنامه اجازه می‌دهد قابل نصب بودن بسته را تأیید کند."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"اتصال به یک تأیید کننده بسته"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"به دارنده اجازه می‎دهد تا تاییدکنندگان بسته را درخواست کند. برای برنامه‎های عادی نیاز نیست."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"دسترسی به درگاه‌های سریال"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"به دارنده اجازه می‌دهد با استفاده از SerialManager API به درگاه‌های سریال دسترسی داشته باشد."</string>
     <string name="save_password_message" msgid="767344687139195790">"می خواهید مرورگر این رمز ورود را به خاطر داشته باشد؟"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"اکنون خیر"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"به خاطر سپردن"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"تأیید"</string>
     <string name="report" msgid="4060218260984795706">"گزارش"</string>
     <string name="wait" msgid="7147118217226317732">"منتظر بمانید"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"این صفحه پاسخ نمی‌دهد."\n\n"آیا می‌خواهید آن را ببندید؟"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"برنامه مجدداً هدایت شد"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> اکنون در حال اجرا است."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ابتدا راه اندازی شد."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 27a9bf4..9cf18ec 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Antaa sovelluksen siirtää tehtäviä etualalle ja taustalle. Haitalliset sovellukset voivat pakottaa itsensä etualalle ilman käyttäjän hallintaa."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"käynnissä olevien sovellusten pysäyttäminen"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Antaa sovelluksen poistaa tehtäviä ja lopettaa niiden sovelluksia. Haitalliset sovellukset voivat häiritä muiden sovellusten toimintaa."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"aseta näytön yhteensopivuus"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Sallii sovelluksen hallita toisten sovellusten näytön yhteensopivuustilaa. Haittasovellukset voivat häiritä toisten sovellusten toimintaa."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"sovellusten vianetsinnän käyttöönotto"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Antaa sovelluksen ottaa vianetsinnän käyttöön toisessa sovelluksessa. Haitalliset ohjelmat voivat lopettaa tällä muita sovelluksia."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuta käyttöliittymäsi asetuksia"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Antaa sovelluksen vahvistaa, että pakkaus on asennettavissa."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sitoudu paketin vahvistajaan"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Antaa sovelluksen tehdä pakettien vahvistuspyyntöjä. Ei tavallisten sovellusten käyttöön."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"käytä sarjaportteja"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Luvan haltija voi käyttää sarjaportteja SerialManager-sovellusliittymän avulla."</string>
     <string name="save_password_message" msgid="767344687139195790">"Haluatko selaimen muistavan tämän salasanan?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ei nyt"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Muista"</string>
@@ -776,7 +780,7 @@
     <string name="searchview_description_query" msgid="5911778593125355124">"Hakulauseke"</string>
     <string name="searchview_description_clear" msgid="1330281990951833033">"Tyhjennä kysely"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"Lähetä kysely"</string>
-    <string name="searchview_description_voice" msgid="2453203695674994440">"Äänihaku"</string>
+    <string name="searchview_description_voice" msgid="2453203695674994440">"Puhehaku"</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"kuukausi sitten"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Yli kuukausi sitten"</string>
   <plurals name="num_seconds_ago">
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Ilmoita"</string>
     <string name="wait" msgid="7147118217226317732">"Odota"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Sivu ei vastaa."\n\n"Haluatko sulkea sen?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Sovelluksen uud.ohjaus"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> on nyt käynnissä."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> käynnistettiin alun perin."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c647570..33b0f45 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permet à l\'application de faire passer les tâches de premier plan en arrière-plan. Des applications malveillantes peuvent exploiter cette fonctionnalité pour passer au premier plan sans votre consentement."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"arrêter les applications en cours d\'exécution"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet à l\'application de supprimer des tâches et de fermer les applications qui les exécutent. Des applications malveillantes peuvent exploiter cette fonctionnalité pour perturber le comportement des autres applications."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"définir la compatibilité de l\'écran"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permettre de contrôler le mode de compatibilité de l\'écran des autres applications. Des applications malveillantes peuvent perturber le fonctionnement d\'autres applications."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"activer le débogage des applications"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permet à l\'application d\'activer le débogage d\'une autre application. Des applications malveillantes peuvent exploiter cette fonctionnalité pour en fermer d\'autres."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"Modification des paramètres de l\'IU"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet à l\'application de vérifier qu\'un package peut être installé."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associer à un vérificateur de package"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de package. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"accéder aux ports série"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet à l\'application autorisée d\'accéder aux ports série avec l\'API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Pas maintenant"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Mémoriser"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapport"</string>
     <string name="wait" msgid="7147118217226317732">"Attendre"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La page ne répond pas."\n" "\n"Voulez-vous la fermer ?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Application redirigée"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> est maintenant lancée."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Application lancée initialement : <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 3e440ca..91ac5a3 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"एप्लिकेशन को अग्रभूमि और पृष्ठभूमि में कार्यों को ले जाने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके नियंत्रण के बिना स्वयं को बलपूर्वक आगे कर सकते हैं."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्लिकेशन रोकें"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्‍लिकेशन को कार्यों को निकालने और उनके एप्‍लिकेशन समाप्त करने देता है. दुर्भावनापूर्ण एप्‍लिकेशन अन्‍य एप्‍लिकेशन का व्‍यवहार बाधित कर सकते हैं."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"स्‍क्रीन संगतता सेट करें"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"एप्‍लिकेशन को अन्‍य एप्‍लिकेशन के स्‍क्रीन संगतता मोड को नियंत्रित करने देता है. दुर्भावनापूर्ण एप्‍लिकेशन अन्‍य एप्‍लिकेशन का व्‍यवहार बाधित कर सकते हैं."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"एप्‍लिकेशन डीबग करना सक्षम करें"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"एप्लिकेशन को अन्य एप्लिकेशन के लिए डीबग किया जाना चालू करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग अन्य एप्लिकेशन को समाप्त करने के लिए कर सकते हैं."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"अपनी UI सेटिंग बदलें"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"एप्‍लि‍केशन को इंस्‍टॉल करने योग्‍य पैकेज सत्‍यापि‍त करने देता है."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"पैकेज प्रमाणक से आबद्ध करें"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति‍ देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"सीरियल पोर्ट पर पहुंचें"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API का उपयोग करके धारक को सीरियल पोर्ट पर पहुंच प्रदान करता है."</string>
     <string name="save_password_message" msgid="767344687139195790">"क्‍या आप चाहते हैं कि ब्राउज़र पासवर्ड को याद रखे?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"अभी नहीं"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"याद रखें"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"ठीक"</string>
     <string name="report" msgid="4060218260984795706">"रिपोर्ट करें"</string>
     <string name="wait" msgid="7147118217226317732">"प्रतीक्षा करें"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"पृष्ठ प्रतिसाद नहीं दे रहा है."\n\n"क्‍या आप इसे बंद करना चाहते हैं?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"एप्‍लि. रीडायरेक्‍ट किया गया"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> अभी चल रहा है."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> को वास्‍तविक रूप से लॉन्‍च किया गया था."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 460ec88..a60dcfa 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Omogućuje aplikaciji da premjesti zadatke u prednji plan ili pozadinu. Zlonamjerne aplikacije mogu na silu doći u prednji plan bez vašeg nadzora."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zaustavljanje pokrenutih aplikacija"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Omogućuje aplikaciji uklanjanje zadataka i uklanjanje njihovih aplikacija. Zlonamjerne aplikacije mogu poremetiti rad drugih aplikacija."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje zaslona kompatibilnost"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Aplikaciji omogućuje upravljanje načinom kompatibilnosti zaslona drugih aplikacija. Zlonamjerne aplikacije mogu prekinuti takvo ponašanje ostalih aplikacija."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"omogućavanje rješavanja programskih pogrešaka u aplikaciji"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Omogućuje aplikaciji uključivanje uklanjanja programskih pogrešaka za drugu aplikaciju. Zlonamjerne aplikacije mogu na taj način ukloniti druge aplikacije."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"promjena postavki korisničkog sučelja"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Aplikaciji omogućuje da provjeri je li paket moguće instalirati."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vezano uz paketnu provjeru"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Nositelju omogućuje da traži paketnu provjeru. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"pristup serijskim priključcima"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Rukovatelju omogućuje pristup serijskim priključcima pomoću značajke SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Želite li da preglednik zapamti ovu zaporku?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ne sada"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapamti"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"U redu"</string>
     <string name="report" msgid="4060218260984795706">"Izvješće"</string>
     <string name="wait" msgid="7147118217226317732">"Pričekaj"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stranica ne reagira."\n\n"Želite li ju zatvoriti?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplikacija preusmjerena"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvodi sada."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> pokrenuta je prva."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 9278bde..6b789ea 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Lehetővé teszi az alkalmazás számára, hogy feladatokat helyezzen át az előtérből a háttérbe és fordítva. A rosszindulatú alkalmazások az előtérbe helyezhetik magukat az Ön engedélye nélkül."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"futó alkalmazások leállítása"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Lehetővé teszi, hogy az alkalmazás feladatokat távolítson el és leállítsa azok alkalmazásait. Rosszindulatú alkalmazások megzavarhatják más alkalmazások viselkedését."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Képernyő-kompatibilitás beállítása"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Lehetővé teszi, hogy az alkalmazás szabályozza az egyéb alkalmazások képernyő-kompatibilitási módját. A kártékony alkalmazások megzavarhatják a többi alkalmazás viselkedését."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"alkalmazások hibakeresésének bekapcsolása"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Lehetővé teszi az alkalmazás számára, hogy hibakeresést végezzen egy másik alkalmazáson. A rosszindulatú alkalmazások ezzel leállíthatnak más alkalmazásokat."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"a felhasználói felület beállításainak módosítása"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lehetővé teszi az alkalmazás számára, hogy ellenőrizze, egy csomag telepíthető-e."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"egy csomaghitelesítőhöz kötődnek"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lehetővé teszi, hogy a tulajdonos kérelmeket nyújtson be a csomag hitelesítőivel kapcsolatban. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"soros portok elérése"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Lehetővé teszi a tulajdonos számára a soros portok elérését a SerialManager API segítségével."</string>
     <string name="save_password_message" msgid="767344687139195790">"Szeretné, hogy a böngésző megjegyezze a jelszót?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Most nem"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Megjegyzés"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Jelentés"</string>
     <string name="wait" msgid="7147118217226317732">"Várakozás"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Az oldal nem válaszol."\n\n"Szeretné bezárni?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Alkalmazás átirányítva"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> éppen fut."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> volt eredetileg elindítva."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 30fb875..6ed5c0e 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Mengizinkan apl memindah tugas ke latar depan dan latar belakang. Apl berbahaya dapat memaksa berpindah ke depan tanpa kontrol Anda."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"menghentikan apl yang berjalan"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Memungkinkan apl menghapus tugas dan menutup aplikasinya. Apl berbahaya dapat mengganggu perilaku apl lain."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"menyetel kompatibilitas layar"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Memungkinkan apl mengontrol mode kompatibilitas layar aplikasi lain. Aplikasi berbahaya dapat merusak perilaku aplikasi lain."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"mengaktifkan debugging apl"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Mengizinkan apl mengaktifkan debugging untuk apl lain. Apl berbahaya dapat menggunakan cara ini untuk menutup apl lain."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"ubah setelan UI Anda"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Mengizinkan apl memverifikasi bahwa suatu paket dapat dipasang."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"mengikat ke pemverifikasi paket"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Mengizinkan pemegang mengajukan permintaan pemverifikasian paket. Tidak pernah dibutuhkan oleh apl normal."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"akses port serial"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Memungkinkan pemegangnya mengakses port serial menggunakan API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Apakah Anda ingin peramban menyimpan sandi ini?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Tidak sekarang"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Laporkan"</string>
     <string name="wait" msgid="7147118217226317732">"Tunggu"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak menanggapi."\n\n"Apakah Anda ingin menutupnya?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Apl dialihkan"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah diluncurkan aslinya."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 2cc182f..8af1f5e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Consente all\'applicazione di spostare attività in primo piano e in background. Le applicazioni dannose potrebbero forzare la loro impostazione in primo piano senza il tuo controllo."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"interruzione applicazioni in esecuzione"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Consente all\'applicazione di rimuovere le attività e terminare le loro applicazioni. Le applicazioni dannose potrebbero interferire con il comportamento di altre applicazioni."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"impostazione compatibilità schermo"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Consente all\'applicazione di controllare la modalità di compatibilità dello schermo di altre applicazioni. Le applicazioni dannose potrebbero disturbare il comportamento di altre applicazioni."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"attivazione debug delle applicazioni"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Consente all\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose potrebbero farne uso per terminare altre applicazioni."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifica impostazioni UI"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Consente all\'applicazione di verificare se un pacchetto è installabile."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associazione a verifica pacchetto"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Consente al proprietario di effettuare richieste relative alle verifiche dei pacchetti. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"accesso alle porte seriali"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Permette al proprietario di accedere alle porte seriali utilizzando l\'API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Memorizzare la password nel browser?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Non ora"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Memorizza"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Segnala"</string>
     <string name="wait" msgid="7147118217226317732">"Attendi"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"La pagina non risponde più."\n\n"Vuoi chiuderla?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Applicazione reindirizzata"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> è ora in esecuzione."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> già avviata."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index e9dd004..5d5b9da 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"מאפשר ליישום להעביר משימות לחזית ולרקע. יישומים זדוניים עלולים לאלץ את עצמם לעבור לחזית ללא שליטה מצדך."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"עצירת יישומים פעילים"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"הרשאה זו מאפשרת ליישום להסיר משימות ולסגור את היישומים שבהם הן פועלות. יישומים זדוניים עלולים לשבש את פעולתם של יישומים אחרים."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"הגדרת תאימות מסך"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"מאפשר ליישום לשלוט במצב תאימות המסך של יישומים אחרים. יישומים זדוניים עלולים לפגוע בהתנהגות של יישומים אחרים."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"הפעלה של ניקוי באגים ביישומים"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"הרשאה זו מאפשרת ליישום להפעיל ניקוי באגים עבור יישום אחר. יישומים זדוניים עלולים להשתמש באפשרות זו כדי לסגור יישומים אחרים."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"שנה את הגדרות ממשק המשתמש שלך"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"מאפשר ליישום לאמת שחבילה ניתנת להתקנה."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"הכפפה למאמת חבילה"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"מאפשר למשתמש להגיש בקשות של מאמתי חבילות. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"גישה ליציאות טוריות"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"מאפשר לבעלים לגשת ליציאות טוריות באמצעות ממשק ה- API של SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"האם ברצונך שהדפדפן יזכור סיסמה זו?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"לא כעת"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"זכור"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"אישור"</string>
     <string name="report" msgid="4060218260984795706">"שלח דוח"</string>
     <string name="wait" msgid="7147118217226317732">"המתן"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"הדף אינו מגיב."\n\n"האם אתה רוצה לסגור אותו?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"הפנייה מחדש של יישום"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> פועל כעת."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> הופעל במקור."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 234f64c..ea4af66 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリに許可します。この許可を悪意のあるアプリに利用されると、悪意のあるアプリが強制的に優先される恐れがあります。"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"実行中のアプリの停止"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"タスクの削除とアプリの終了をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、他のアプリの動作が妨害される恐れがあります。"</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"アプリのデバッグの有効化"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"別のアプリをデバッグモードにすることをアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリが強制終了される恐れがあります。"</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI設定の変更"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"パッケージがインストール可能かどうか確認することをアプリに許可します。"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"パッケージベリファイアにバインド"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"パッケージベリファイアのリクエストを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"シリアルポートへのアクセス"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager APIを使用してシリアルポートにアクセスすることを所有者に許可します。"</string>
     <string name="save_password_message" msgid="767344687139195790">"このパスワードをブラウザで保存しますか?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"今は保存しない"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"保存"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"レポート"</string>
     <string name="wait" msgid="7147118217226317732">"待機"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"ページが応答しません。"\n\n"ページを閉じますか?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"アプリのリダイレクト"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>が実行中です。"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>が最初に起動していました。"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 804110c..2c664c9 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"앱이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자의 조작 없이 앞으로 이동할 수 있습니다."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"실행 중인 앱 중지"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"애플리케이션이 작업을 삭제하거나 다른 애플리케이션을 중지시킬 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션의 동작을 멈추게 할 수 있습니다."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"앱 디버깅 사용"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"애플리케이션이 다른 애플리케이션에 대해 디버깅을 사용할 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션을 중지시킬 수 있습니다."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI 설정 변경"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"앱이 패키지가 설치 가능한지 확인할 수 있도록 허용합니다."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"패키지 인증 연결"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"권한을 가진 프로그램이 패키지 인증을 요청할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"직렬 포트에 액세스"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API를 사용하여 권한을 가진 프로그램이 직렬 포트에 액세스할 수 있도록 합니다."</string>
     <string name="save_password_message" msgid="767344687139195790">"브라우저에 이 비밀번호를 저장하시겠습니까?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"나중에"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"저장"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"확인"</string>
     <string name="report" msgid="4060218260984795706">"신고"</string>
     <string name="wait" msgid="7147118217226317732">"대기"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"페이지가 응답하지 않습니다."\n\n"페이지를 닫으시겠습니까?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"앱 리디렉션됨"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>이(가) 실행 중입니다."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"원래 <xliff:g id="APP_NAME">%1$s</xliff:g>을(를) 실행했습니다."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9d6bd77..22830ac 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Leidžiama programai užduotis perkelti į priekinį planą ir į foną. Kenkėjiškos programos gali priverstinai persikelti į priekį be jūsų įsikišimo."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"sustabdyti vykdomas programas"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Leidžiama programai pašalinti užduotis ir panaikinti jų programas. Kenkėjiškos programos gali trikdyti kitų programų veikimą."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nustatyti ekrano suderinamumo režimą"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Programai leidžiama valdyti kitų programų ekrano suderinamumo režimą. Kenkėjiškos programos gali kliudyti veikti kitoms programoms."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"įgalinti programos derinimą"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Leidžiama programai įjungti kitos programos derinimą. Kenkėjiškos programos gali tai naudoti, kad išjungtų kitas programas."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"keisti UI nustatymus"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Leidžiama programai patikrinti, ar paketą galima įdiegti."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"susaistyti su paketo tikrinimo programa"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Savininkui leidžiama teikti užklausas patikrinti paketą. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"pasiekti nuosekliuosius prievadus"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Leidžiama savininkui pasiekti nuosekliuosius prievadus naudojant „SerialManager“ API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Ar norite, kad naršyklė atsimintų šį slaptažodį?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ne dabar"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Atsiminti"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"Gerai"</string>
     <string name="report" msgid="4060218260984795706">"Ataskaita"</string>
     <string name="wait" msgid="7147118217226317732">"Palaukti"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Puslapis neatsako."\n\n"Ar norite jį uždaryti?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Programa peradresuota"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ dabar vykdoma."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ buvo iš pradžių paleista."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 195059c..f716cb9 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ļauj lietotnei pārvietot uzdevumus priekšplānā un fonā. Ļaunprātīgas lietotnes var tikt izvirzītas priekšplānā bez jūsu vadības."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"apturēt izmantoto lietotņu darbību"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Ļauj lietotnei noņemt uzdevumus un pārtraukt to lietotņu darbību. Ļaunprātīgas lietotnes var traucēt citu lietotņu darbību."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Ekrāna saderības noteikšana"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ļauj lietotnei kontrolēt citu lietotņu ekrāna saderības režīmu. Ļaunprātīgas lietojumprogrammas var mainīt citu lietojumprogrammu darbību."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"iespējot lietotnes atkļūdošanu"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ļauj lietotnei ieslēgt citas lietotnes atkļūdošanu. Ļaunprātīgas lietotnes to var izmantot, lai pārtrauktu citu lietotņu darbību."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"mainīt lietotāja saskarnes iestatījumus"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ļauj lietotnei verificēt, vai pakotne ir instalējama."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"saistīšana ar pakotnes verificētāju"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ļauj īpašniekam sūtīt pakotņu verificētāju pieprasījumus. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"piekļuve seriālajiem portiem"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Ļauj īpašniekam piekļūt seriālajiem portiem, izmantojot SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Vai vēlaties, lai pārlūkprogrammā tiktu saglabāta šī parole?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ne tagad"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Atcerēties"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"Labi"</string>
     <string name="report" msgid="4060218260984795706">"Pārskats"</string>
     <string name="wait" msgid="7147118217226317732">"Gaidīt"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"No lapas netiek saņemta atbilde."\n\n"Vai vēlaties to aizvērt?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Lietotne ir novirzīta"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> tagad darbojas."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Sākotnēji tika palaista lietojumprogramma <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a8e733f..659a7ad 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Membenarkan apl untuk memindahkan tugasan ke latar depan dan latar belakang. Apl hasad boleh memaksa diri mereka ke hadapan tanpa kawalan anda."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"hentikan apl yang sedang dijalankan"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Membenarkan apl untuk mengalih keluar tugasan dan melupuskan aplnya. Apl hasad boleh mengganggu tingkah laku apl lain."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"dayakan penyahpepijatan apl"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Membenarkan apl untuk menghidupkan penyahpepijatan untuk apl lain. Apl hasad boleh menggunakannya untuk menghapuskan apl lain."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"tukar tetapan UI anda"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Membenarkan apl untuk mengesahkan bahawa pakej boleh dipasang."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ikat kepada pengesah pakej"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Membenarkan pemegang membuat permintaan pengesah pakej. Tidak sekali-kali diperlukan untuk apl normal."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"akses port bersiri"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Membenarkan pemegang mengakses port bersiri menggunakan API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Adakah anda mahu penyemak imbas mengingati kata laluan ini?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Bukan sekarang"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Laporkan"</string>
     <string name="wait" msgid="7147118217226317732">"Tunggu"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak bertindak balas. "\n\n"Adakah anda mahu menutupnya?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Apl diubah hala"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kini sedang berjalan."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> pada asalnya telah dilancarkan."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 7e3fb86..b1b3cbe 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Lar appen flytte oppgaver til forgrunnen eller bakgrunnen. Ondsinnede apper kan tvinge seg frem til forgrunnen utenfor din kontroll."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"avslutte apper som kjører"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Lar appen fjerne oppgaver og avslutte apper. Ondsinnede apper kan forstyrre atferden til andre apper."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"angi skjermkompatibilitet"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Lar appen kontrollere modus for skjermkompatibilitet i andre apper. Skadelige apper kan ødelegge funksjoner i andre apper."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivere feilsøking av app"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Lar appen slå av feilsøking for andre apper. Ondsinnede apper kan bruke dette til å avslutte andre apper."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"endre innstillingene for brukergrensesnitt"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lar appen bekrefte om en pakke kan installeres."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en pakkeverifikator"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lar innehaveren sende forespørsler om pakkeverifikatorer. Skal aldri være nødvendig for normale apper."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"tilgang til serielle porter"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Gir innehaveren tilgang til serielle porter ved hjelp av SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Ønsker du at nettleseren skal huske dette passordet?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nå"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapportér"</string>
     <string name="wait" msgid="7147118217226317732">"Vent"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Siden svarer ikke."\n\n"Vil du lukke den?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Appen er viderekoblet"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kjører nå."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ble opprinnelig startet."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b956433..9409445 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Hiermee kan de app taken naar de voor- en achtergrond verplaatsen. Schadelijke apps kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"actieve apps stoppen"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Hiermee kan de app taken verwijderen en apps sluiten. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"schermcompatibiliteit instellen"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Toestaan dat de app de schermcompatibiliteitsmodus van andere apps beheert. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"foutopsporing in apps inschakelen"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Hiermee kan de app de foutopsporing voor een andere app inschakelen. Schadelijke apps kunnen dit gebruiken om andere apps af te sluiten."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"uw UI-instellingen wijzigen"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Hiermee kan de app controleren of een pakket kan worden geïnstalleerd."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"koppelen aan pakketcontroleprogramma"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Hiermee kan de houder verzoeken indienen voor pakketcontroles. Nooit vereist voor normale apps."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"toegang krijgen tot seriële poorten"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"De houder toestaan toegang tot seriële poorten te krijgen met de SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapport"</string>
     <string name="wait" msgid="7147118217226317732">"Wachten"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"De pagina reageert niet meer."\n\n"Wilt u de pagina sluiten?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"App verplaatst"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nu actief."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was het eerst gestart."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 9c713aa..8564dc7 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Pozwala aplikacji na przenoszenie zadań między tłem i pierwszym planem. Złośliwe aplikacje mogą wymusić przeniesienie się na pierwszy plan bez Twojego udziału."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zatrzymywanie uruchomionych aplikacji"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umożliwia aplikacji usuwanie zadań i kończenie powiązanych z nimi aplikacji. Złośliwe aplikacje mogą zakłócić działanie innych aplikacji."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ustaw zgodność ekranu"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pozwala aplikacji na sterowanie trybem zgodności ekranu innych aplikacji. Złośliwe aplikacje mogą zmienić zachowanie innych aplikacji."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"włączenie debugowania aplikacji"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Złośliwe aplikacje mogą to wykorzystać do kończenia pracy innych programów."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmienianie ustawień interfejsu użytkownika"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pozwala aplikacji na zweryfikowanie, czy pakiet można zainstalować."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"powiązanie z weryfikatorem pakietów"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pozwala na wysyłanie żądań weryfikacji pakietu. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"dostęp do portów szeregowych"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Umożliwia posiadaczowi dostęp do portów szeregowych przy użyciu interfejsu API narzędzia SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nie teraz"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapamiętaj"</string>
@@ -908,13 +912,14 @@
     <string name="aerr_application" msgid="932628488013092776">"Niestety, aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> została zatrzymana."</string>
     <string name="aerr_process" msgid="4507058997035697579">"Niestety, proces <xliff:g id="PROCESS">%1$s</xliff:g> został zatrzymany."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikacja <xliff:g id="APPLICATION">%2$s</xliff:g> nie odpowiada."\n\n"Czy chcesz ją zamknąć?"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"Aplikacja <xliff:g id="APPLICATION">%2$s</xliff:g> nie reaguje."\n\n"Czy chcesz ją zamknąć?"</string>
     <string name="anr_activity_process" msgid="5776209883299089767">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> nie odpowiada."\n\n"Czy chcesz je zakończyć?"</string>
-    <string name="anr_application_process" msgid="8941757607340481057">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> nie odpowiada. Czy chcesz ją zamknąć?"</string>
+    <string name="anr_application_process" msgid="8941757607340481057">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> nie reaguje. Czy chcesz ją zamknąć?"</string>
     <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nie odpowiada."\n\n"Czy chcesz go zakończyć?"</string>
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Zgłoś"</string>
     <string name="wait" msgid="7147118217226317732">"Czekaj"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Strona nie odpowiada na żądania."\n\n"Zamknąć ją?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplikacja przekierowana"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest uruchomiona."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> została pierwotnie uruchomiona."</string>
@@ -1214,12 +1219,12 @@
     <string name="ssl_certificate" msgid="6510040486049237639">"Certyfikat zabezpieczeń"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Certyfikat jest ważny."</string>
     <string name="issued_to" msgid="454239480274921032">"Wystawiony dla:"</string>
-    <string name="common_name" msgid="2233209299434172646">"Nazwa pospolita (CN):"</string>
+    <string name="common_name" msgid="2233209299434172646">"Nazwa (CN):"</string>
     <string name="org_name" msgid="6973561190762085236">"Organizacja:"</string>
     <string name="org_unit" msgid="7265981890422070383">"Jednostka organizacyjna:"</string>
     <string name="issued_by" msgid="2647584988057481566">"Wystawca:"</string>
     <string name="validity_period" msgid="8818886137545983110">"Ważność:"</string>
-    <string name="issued_on" msgid="5895017404361397232">"Data wystawienia:"</string>
+    <string name="issued_on" msgid="5895017404361397232">"Wystawiony:"</string>
     <string name="expires_on" msgid="3676242949915959821">"Wygasa:"</string>
     <string name="serial_number" msgid="758814067660862493">"Numer seryjny:"</string>
     <string name="fingerprints" msgid="4516019619850763049">"Odciski cyfrowe:"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index c5e470c..a162aa0 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite à aplicação mover tarefas para primeiro e segundo plano. As aplicações maliciosas podem impor-se em primeiro plano sem o controlo do utilizador."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"parar aplicações em execução"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que a aplicação remova tarefas e elimine as respetivas aplicações. As aplicações maliciosas podem perturbar o comportamento de outras aplicações."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definir compatibilidade de ecrã"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite que a aplicação controle o modo de compatibilidade de ecrã de outras aplicações. As aplicações maliciosas poderão afetar o comportamento de outras aplicações."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"ativar depuração da aplicação"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que a aplicação ative a depuração para outra aplicação. As aplicações maliciosas podem utilizar isto para eliminar outras aplicações."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar definições da IU"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que a aplicação verifique se um pacote é instalável."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacotes"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite ao titular solicitar verificadores de pacotes. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"aceder a portas série"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite ao titular aceder a portas de série através da API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Quer que o browser memorize esta palavra-passe?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Relatório"</string>
     <string name="wait" msgid="7147118217226317732">"Esperar"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"A página deixou de responder. "\n" "\n" Pretende fechá-la?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicação redirecionada"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> está agora a ser executado."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi originalmente iniciado."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 10ac03f..4915a233 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que o aplicativo mova tarefas para o primeiro plano e para o plano de fundo. Aplicativos maliciosos podem forçar-se para a primeiro plano sem que você tenha controle sobre a ação."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"parar os aplicativos em execução"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que um aplicativo remova tarefas e elimine seus aplicativos. Aplicativos maliciosos podem interferir no comportamento de outros aplicativos."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"ativar depuração do aplicativo"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que o aplicativo ative a depuração para outro aplicativo. Aplicativos maliciosos podem usar esse recurso para cancelar outros aplicativos."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar as suas configurações de UI"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que o aplicativo verifique se um pacote pode ser instalado."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacote"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que o titular solicite verificadores de pacote. Nunca deve ser necessário para aplicativos normais."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"acessar portas seriais"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite que o detentor tenha acesso a portas seriais usando a API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Deseja que o navegador lembre desta senha?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Informar"</string>
     <string name="wait" msgid="7147118217226317732">"Aguardar"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"A página não responde."\n\n"Deseja fechá-la?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicativo redirecionado"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> não está em execução."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi iniciado."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 4d40ddc..57daee7 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -27,7 +27,8 @@
     <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
     <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
     <string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
-    <!-- outdated translation 6071602020171759109 -->     <string name="untitled" msgid="4638956954852782576">"&lt;senza titel&gt;"</string>
+    <!-- no translation found for untitled (4638956954852782576) -->
+    <skip />
     <string name="ellipsis" msgid="7899829516048813237">"…"</string>
     <!-- no translation found for ellipsis_two_dots (1228078994866030736) -->
     <skip />
@@ -44,9 +45,12 @@
     <string name="serviceErased" msgid="1288584695297200972">"Stizzà cun success."</string>
     <string name="passwordIncorrect" msgid="7612208839450128715">"Il pled-clav è nuncorrect."</string>
     <string name="mmiComplete" msgid="8232527495411698359">"MMI terminà."</string>
-    <!-- outdated translation 5085454289896032547 -->     <string name="badPin" msgid="9015277645546710014">"Il code PIN vegl che Vus avais endatà è nuncorrect."</string>
-    <!-- outdated translation 5702522162746042460 -->     <string name="badPuk" msgid="5487257647081132201">"Il PUK che Vus avais tippà è nuncorrect."</string>
-    <!-- outdated translation 3695902225843339274 -->     <string name="mismatchPin" msgid="609379054496863419">"Ils codes PIN che Vus avais endatà n\'èn betg identics."</string>
+    <!-- no translation found for badPin (9015277645546710014) -->
+    <skip />
+    <!-- no translation found for badPuk (5487257647081132201) -->
+    <skip />
+    <!-- no translation found for mismatchPin (609379054496863419) -->
+    <skip />
     <string name="invalidPin" msgid="3850018445187475377">"Endatai in code PIN che cuntegna 4 fin 8 cifras."</string>
     <!-- no translation found for invalidPuk (8761456210898036513) -->
     <skip />
@@ -70,16 +74,20 @@
     <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"La ID dal telefonader n\'è betg limitada tenor configuraziun predefinida. Proxim clom: limitada."</string>
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"La ID dal telefonader n\'è betg limitada tenor configuraziun predefinida. Proxim clom: betg limitada."</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Quest servetsch na vegn betg sustegnì."</string>
-    <!-- outdated translation 5460892159398802465 -->     <string name="CLIRPermanent" msgid="3377371145926835671">"Il parameter per la ID dal telefonader na po betg vegnir modifitgà."</string>
+    <!-- no translation found for CLIRPermanent (3377371145926835671) -->
+    <skip />
     <string name="RestrictedChangedTitle" msgid="5592189398956187498">"L\'access limità è vegnì modifitgà."</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"Il servetsch da datas è bloccà."</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Il servetsch da cloms d\'urgenza è bloccà."</string>
     <string name="RestrictedOnNormal" msgid="4953867011389750673">"Il servetsch vocal è bloccà."</string>
-    <string name="RestrictedOnAllVoice" msgid="1459318899842232234">"Tut ils servetschs vocals èn bloccads."</string>
+    <!-- no translation found for RestrictedOnAllVoice (3396963652108151260) -->
+    <skip />
     <string name="RestrictedOnSms" msgid="8314352327461638897">"Il servetsch SMS è bloccà."</string>
-    <string name="RestrictedOnVoiceData" msgid="8244438624660371717">"Ils servetschs vocals/da datas èn bloccads."</string>
+    <!-- no translation found for RestrictedOnVoiceData (996636487106171320) -->
+    <skip />
     <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Ils servetschs vocals/dad SMS èn bloccads."</string>
-    <string name="RestrictedOnAll" msgid="2714924667937117304">"Tut ils servetschs vocals/da datas/da SMS èn bloccads."</string>
+    <!-- no translation found for RestrictedOnAll (5643028264466092821) -->
+    <skip />
     <string name="serviceClassVoice" msgid="1258393812335258019">"Vusch"</string>
     <string name="serviceClassData" msgid="872456782077937893">"Datas"</string>
     <string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
@@ -110,35 +118,56 @@
     <string name="fcComplete" msgid="3118848230966886575">"Code da servetsch terminà"</string>
     <string name="fcError" msgid="3327560126588500777">"Problem da connexiun u code da funcziun nunvalid"</string>
     <string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
-    <!-- outdated translation 2567300624552921790 -->     <string name="httpError" msgid="6603022914760066338">"La pagina d\'internet cuntegna ina errur."</string>
-    <string name="httpErrorLookup" msgid="4517085806977851374">"Impussibel da chattar la URL."</string>
-    <!-- outdated translation 2781440683514730227 -->     <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Il schema d\'autentificaziun da la site na vegn betg sustegnì."</string>
-    <string name="httpErrorAuth" msgid="7293960746955020542">"L\'autentificaziun n\'è betg reussida."</string>
+    <!-- no translation found for httpError (7956392511146698522) -->
+    <skip />
+    <!-- no translation found for httpErrorLookup (4711687456111963163) -->
+    <skip />
+    <!-- no translation found for httpErrorUnsupportedAuthScheme (6299980280442076799) -->
+    <skip />
+    <!-- no translation found for httpErrorAuth (1435065629438044534) -->
+    <skip />
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"L\'autentificaziun cun agid dad in proxy server n\'è betg reussida."</string>
-    <string name="httpErrorConnect" msgid="7623096283505770433">"Betg reussì da connectar cun il server."</string>
-    <!-- outdated translation 5047872902739125260 -->     <string name="httpErrorIO" msgid="4270874999047767599">"La communicaziun cun il server n\'è betg reussida. Empruvai pli tard anc ina giada."</string>
+    <!-- no translation found for httpErrorConnect (8714273236364640549) -->
+    <skip />
+    <!-- no translation found for httpErrorIO (2340558197489302188) -->
+    <skip />
     <string name="httpErrorTimeout" msgid="4743403703762883954">"Surpassà il temp cun connectar al server."</string>
     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Questa pagina cuntegna memia blers renviaments da server."</string>
-    <!-- outdated translation 5257172771607996054 -->     <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Quest protocol na vegn betg sustegnì."</string>
-    <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Impussibel da stabilir ina connexiun segira."</string>
-    <string name="httpErrorBadUrl" msgid="6088183159988619736">"Impussibel dad avrir la pagina. La URL è nunvalida."</string>
-    <string name="httpErrorFile" msgid="8250549644091165175">"Impussibel d\'acceder a la datoteca."</string>
-    <string name="httpErrorFileNotFound" msgid="5588380756326017105">"La datoteca dumandada n\'è betg vegnida chattada."</string>
+    <!-- no translation found for httpErrorUnsupportedScheme (5015730812906192208) -->
+    <skip />
+    <!-- no translation found for httpErrorFailedSslHandshake (96549606000658641) -->
+    <skip />
+    <!-- no translation found for httpErrorBadUrl (3636929722728881972) -->
+    <skip />
+    <!-- no translation found for httpErrorFile (2170788515052558676) -->
+    <skip />
+    <!-- no translation found for httpErrorFileNotFound (6203856612042655084) -->
+    <skip />
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Actualmain vegnan memia bleras dumondas elavuradas. Empruvai pli tard anc ina giada."</string>
-    <string name="notification_title" msgid="1259940370369187045">"Errur cun connectar al conto <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+    <!-- no translation found for notification_title (8967710025036163822) -->
+    <skip />
     <string name="contentServiceSync" msgid="8353523060269335667">"Sincronisar"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronisar"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Memia blers cuntegns stizzads (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
-    <!-- outdated translation 6632412458436461203 -->     <string name="low_memory" product="tablet" msgid="2292820184396262278">"La memoria dal telefon è occupada! Stizzai datotecas per crear capacitad da memorisar."</string>
-    <string name="low_memory" product="default" msgid="6632412458436461203">"La memoria dal telefon è occupada! Stizzai datotecas per crear capacitad da memorisar."</string>
+    <!-- no translation found for low_memory (6494019234102154896) -->
+    <skip />
+    <!-- no translation found for low_memory (3475999286680000541) -->
+    <skip />
     <string name="me" msgid="6545696007631404292">"Jau"</string>
-    <!-- outdated translation 1319919075463988638 -->     <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opziuns dal telefon"</string>
+    <!-- no translation found for power_dialog (8545351420865202853) -->
+    <skip />
     <string name="power_dialog" product="default" msgid="1319919075463988638">"Opziuns dal telefon"</string>
     <string name="silent_mode" msgid="7167703389802618663">"Modus silenzius"</string>
     <string name="turn_on_radio" msgid="3912793092339962371">"Activar il modus senza fil"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Deactivar il modus senza fil"</string>
     <string name="screen_lock" msgid="799094655496098153">"Bloccaziun dal visur"</string>
     <string name="power_off" msgid="4266614107412865048">"Serrar"</string>
+    <!-- no translation found for silent_mode_silent (319298163018473078) -->
+    <skip />
+    <!-- no translation found for silent_mode_vibrate (7072043388581551395) -->
+    <skip />
+    <!-- no translation found for silent_mode_ring (8592241816194074353) -->
+    <skip />
     <string name="shutdown_progress" msgid="2281079257329981203">"Vegn serrà..."</string>
     <!-- no translation found for shutdown_confirm (3385745179555731470) -->
     <skip />
@@ -147,8 +176,10 @@
     <!-- no translation found for shutdown_confirm_question (2906544768881136183) -->
     <skip />
     <string name="recent_tasks_title" msgid="3691764623638127888">"Utilisà sco ultim"</string>
-    <!-- outdated translation 279702952298056674 -->     <string name="no_recent_tasks" msgid="8794906658732193473">"Naginas applicaziuns utilisadas dacurt"</string>
-    <!-- outdated translation 2406416831541615258 -->     <string name="global_actions" product="tablet" msgid="408477140088053665">"Opziuns dal telefon"</string>
+    <!-- no translation found for no_recent_tasks (8794906658732193473) -->
+    <skip />
+    <!-- no translation found for global_actions (408477140088053665) -->
+    <skip />
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opziuns dal telefon"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloccaziun dal visur"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Metter ord funcziun"</string>
@@ -163,16 +194,21 @@
     <string name="safeMode" msgid="2788228061547930246">"Modus segirà"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servetschs che custan"</string>
-    <!-- outdated translation 8193824940620517189 -->     <string name="permgroupdesc_costMoney" msgid="8596717365335027057">"Permetta ad applicaziuns dad exequir acziuns che custan eventualmain."</string>
+    <!-- no translation found for permgroupdesc_costMoney (3293301903409869495) -->
+    <skip />
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Voss messadis"</string>
-    <!-- outdated translation 7045736972019211994 -->     <string name="permgroupdesc_messages" msgid="7821999071003699236">"\"Leger e scriver Voss SMS, e-mails ed auters messadis.\""</string>
+    <!-- no translation found for permgroupdesc_messages (7821999071003699236) -->
+    <skip />
     <string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Vossas infurmaziuns persunalas"</string>
-    <!-- outdated translation 5488050357388806068 -->     <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Acceder directamain als contacts ed al chalender memorisà sin il telefonin."</string>
+    <!-- no translation found for permgroupdesc_personalInfo (6975389054186265786) -->
+    <skip />
     <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Acceder directamain als contacts ed al chalender memorisà sin il telefonin."</string>
     <string name="permgrouplab_location" msgid="635149742436692049">"Vossa posiziun"</string>
-    <string name="permgroupdesc_location" msgid="2430258821648348660">"suandar Vossa posiziun geografica"</string>
+    <!-- no translation found for permgroupdesc_location (5704679763124170100) -->
+    <skip />
     <string name="permgrouplab_network" msgid="5808983377727109831">"Communicaziun rait"</string>
-    <!-- outdated translation 5035763698958415998 -->     <string name="permgroupdesc_network" msgid="4917593670797570584">"Permetta ad applicaziuns l\'access a differentas funcziuns da la rait."</string>
+    <!-- no translation found for permgroupdesc_network (4478299413241861987) -->
+    <skip />
     <string name="permgrouplab_accounts" msgid="3359646291125325519">"Voss contos"</string>
     <string name="permgroupdesc_accounts" msgid="4948732641827091312">"Access als contos disponibels"</string>
     <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Cumonds da la hardware"</string>
@@ -182,62 +218,94 @@
     <string name="permgrouplab_systemTools" msgid="4652191644082714048">"Utensils da sistem"</string>
     <string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Access e controlla sin nivel datiers al sistem."</string>
     <string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Utensils per sviluppaders"</string>
-    <!-- outdated translation 9056431193893809814 -->     <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"Questas funcziunalitads èn mo previsas per ils sviluppaders dad applicaziuns."</string>
+    <!-- no translation found for permgroupdesc_developmentTools (7058828032358142018) -->
+    <skip />
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Memoria"</string>
-    <!-- outdated translation 9203302214915355774 -->     <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Access a la carta SD."</string>
+    <!-- no translation found for permgroupdesc_storage (7442318502446874999) -->
+    <skip />
     <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Access a la carta SD."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"deactivar u modifitgar la trav da status"</string>
-    <!-- outdated translation 1365473595331989732 -->     <string name="permdesc_statusBar" msgid="8434669549504290975">"Permetta a l\'applicaziun da deactivar l\'indicatur da status u agiuntar ed allontanar simbols dal sistem."</string>
+    <!-- no translation found for permdesc_statusBar (8434669549504290975) -->
+    <skip />
     <string name="permlab_statusBarService" msgid="7247281911387931485">"trav da status"</string>
-    <!-- outdated translation 4097605867643520920 -->     <string name="permdesc_statusBarService" msgid="716113660795976060">"Permetta a l\'applicaziun dad esser la trav da status."</string>
+    <!-- no translation found for permdesc_statusBarService (716113660795976060) -->
+    <skip />
     <string name="permlab_expandStatusBar" msgid="1148198785937489264">"expander/reducir la trav da status"</string>
-    <!-- outdated translation 7088604400110768665 -->     <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Permetta a l\'applicaziun da mussar u zuppentar la trav da status."</string>
+    <!-- no translation found for permdesc_expandStatusBar (6917549437129401132) -->
+    <skip />
     <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar cloms sortints"</string>
-    <!-- outdated translation 2228988201852654461 -->     <string name="permdesc_processOutgoingCalls" msgid="1152111671618301044">"\"Permetta ad ina applicaziun dad elavurar ils cloms sortints e da modifitgar il numer che duai vegnir cumponì. Applicaziuns donnegiusas pon uschia eventualmain survegliar, renviar u evitar cloms sortints.\""</string>
+    <!-- no translation found for permdesc_processOutgoingCalls (1152111671618301044) -->
+    <skip />
     <string name="permlab_receiveSms" msgid="2697628268086208535">"retschaiver SMS"</string>
-    <!-- outdated translation 6298292335965966117 -->     <string name="permdesc_receiveSms" msgid="8107887121893611793">"Permetta a l\'applicaziun da retschaiver ed elavurar SMS. Applicaziuns donnegiusas pon uschia survegliar Voss messadis u als stizzar avant ch\'els vegnan mussads."</string>
+    <!-- no translation found for permdesc_receiveSms (8107887121893611793) -->
+    <skip />
     <string name="permlab_receiveMms" msgid="8894700916188083287">"retschaiver MMS"</string>
-    <!-- outdated translation 4563346832000174373 -->     <string name="permdesc_receiveMms" msgid="1424805308566612086">"Permetta a l\'applicaziun da retschaiver ed elavurar MMS. Applicaziuns donnegiusas pon uschia survegliar Voss messadis u als stizzar avant ch\'els vegnan mussads."</string>
+    <!-- no translation found for permdesc_receiveMms (1424805308566612086) -->
+    <skip />
     <!-- no translation found for permlab_receiveEmergencyBroadcast (1803477660846288089) -->
     <skip />
     <!-- no translation found for permdesc_receiveEmergencyBroadcast (848524070262431974) -->
     <skip />
     <string name="permlab_sendSms" msgid="5600830612147671529">"trametter messadis SMS"</string>
-    <!-- outdated translation 1946540351763502120 -->     <string name="permdesc_sendSms" msgid="906546667507626156">"Permetta ad applicaziuns da trametter messadis SMS. Applicaziuns donnegiusas pon chaschunar custs cun trametter messadis senza As dumandar."</string>
+    <!-- no translation found for permdesc_sendSms (906546667507626156) -->
+    <skip />
     <!-- no translation found for permlab_sendSmsNoConfirmation (4781483105951730228) -->
     <skip />
     <!-- no translation found for permdesc_sendSmsNoConfirmation (3437759207020400204) -->
     <skip />
     <string name="permlab_readSms" msgid="4085333708122372256">"leger SMS u MMS"</string>
-    <!-- outdated translation 3002170087197294591 -->     <string name="permdesc_readSms" product="tablet" msgid="2341692916884515613">"Permetta ad ina applicaziun da leger ils SMS memorisads sin Voss telefonin u sin Vossa carta SIM. Applicaziuns donnegiusas legian uschia eventualmain Voss messadis confidenzials."</string>
-    <!-- outdated translation 3002170087197294591 -->     <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Permetta ad ina applicaziun da leger ils SMS memorisads sin Voss telefonin u sin Vossa carta SIM. Applicaziuns donnegiusas legian uschia eventualmain Voss messadis confidenzials."</string>
+    <!-- no translation found for permdesc_readSms (2341692916884515613) -->
+    <skip />
+    <!-- no translation found for permdesc_readSms (5653850482025875493) -->
+    <skip />
     <string name="permlab_writeSms" msgid="6881122575154940744">"modifitgar SMS u MMS"</string>
-    <!-- outdated translation 6299398896177548095 -->     <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Permetta ad ina applicaziun da modifitgar SMS memorisads sin Voss telefonin u Vossa carta SIM. Applicaziuns donnegiusas stizzan uschia eventualmain Voss messadis."</string>
-    <!-- outdated translation 6299398896177548095 -->     <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Permetta ad ina applicaziun da modifitgar SMS memorisads sin Voss telefonin u Vossa carta SIM. Applicaziuns donnegiusas stizzan uschia eventualmain Voss messadis."</string>
+    <!-- no translation found for permdesc_writeSms (5160413947794501538) -->
+    <skip />
+    <!-- no translation found for permdesc_writeSms (7268668709052328567) -->
+    <skip />
     <string name="permlab_receiveWapPush" msgid="8258226427716551388">"retschaiver messadis WAP"</string>
-    <!-- outdated translation 5979623826128082171 -->     <string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Permetta a l\'applicaziun da retschaiver ed elavurar messadis WAP. Applicaziuns donnegiusas pon uschia survegliar Voss messadis u als stizzar avant ch\'els vegnan mussads."</string>
-    <!-- outdated translation 5005277531132573353 -->     <string name="permlab_getTasks" msgid="6466095396623933906">"recuperaziun da las applicaziuns exequidas"</string>
-    <!-- outdated translation 7048711358713443341 -->     <string name="permdesc_getTasks" msgid="6608159250520381359">"Permetta a l\'applicaziun da recuperar infurmaziuns davart incumbensas che vegnan exequidas u èn gist vegnidas exequidas. Applicaziuns donnegiusas pon uschia obtegnair infurmaziuns privatas concernent autras applicaziuns."</string>
-    <!-- outdated translation 5669588525059921549 -->     <string name="permlab_reorderTasks" msgid="2018575526934422779">"reorganisar las applicaziuns che vegnan exequidas"</string>
-    <!-- outdated translation 126252774270522835 -->     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permetta ad ina applicaziun da spustar las incumbensas en il fund davant u en il fund davos. Applicaziuns donnegiusas pon sa mussar en il fund davant senza Vossa autorisaziun."</string>
+    <!-- no translation found for permdesc_receiveWapPush (7983455145335316872) -->
+    <skip />
+    <!-- no translation found for permlab_getTasks (6466095396623933906) -->
+    <skip />
+    <!-- no translation found for permdesc_getTasks (6608159250520381359) -->
+    <skip />
+    <!-- no translation found for permlab_reorderTasks (2018575526934422779) -->
+    <skip />
+    <!-- no translation found for permdesc_reorderTasks (4175137612205663399) -->
+    <skip />
     <!-- no translation found for permlab_removeTasks (6821513401870377403) -->
     <skip />
-    <!-- no translation found for permdesc_removeTasks (1000226123143185094) -->
+    <!-- no translation found for permdesc_removeTasks (1394714352062635493) -->
     <skip />
-    <!-- outdated translation 4339730312925176742 -->     <string name="permlab_setDebugApp" msgid="3022107198686584052">"activar il debugging da l\'applicaziun"</string>
-    <!-- outdated translation 5584310661711990702 -->     <string name="permdesc_setDebugApp" msgid="6215654419903651172">"Permetta ad ina applicaziun dad activar il debugging per autras applicaziuns. Applicaziuns donnegiusas pon uschia serrar autras applicaziuns."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
+    <!-- no translation found for permlab_setDebugApp (3022107198686584052) -->
+    <skip />
+    <!-- no translation found for permdesc_setDebugApp (4474512416299013256) -->
+    <skip />
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifitgar ils parameters da la UI"</string>
-    <!-- outdated translation 3465121501528064399 -->     <string name="permdesc_changeConfiguration" msgid="4104052649900380324">"Permetta ad ina applicaziun da modifitgar la configuraziun actuala (per exempel la grondezza da la scrittira ed ils parameters regiunals)."</string>
+    <!-- no translation found for permdesc_changeConfiguration (4372223873154296076) -->
+    <skip />
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"activar il modus dad auto"</string>
-    <!-- outdated translation 5673461159384850628 -->     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permetta ad ina applicaziun dad activar il modus dad auto."</string>
+    <!-- no translation found for permdesc_enableCarMode (4853187425751419467) -->
+    <skip />
     <string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"interrumper ils process en il fund davos"</string>
-    <!-- outdated translation 2908829602869383753 -->     <string name="permdesc_killBackgroundProcesses" msgid="931129103262126617">"Permetta ad ina applicaziun da serrar process en il fund davos dad autras applicaziuns era en cas da memoria suffizienta."</string>
-    <!-- outdated translation 1447830113260156236 -->     <string name="permlab_forceStopPackages" msgid="2329627428832067700">"serrar autras applicaziuns cun forza"</string>
-    <!-- outdated translation 7263036616161367402 -->     <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Permetta ad ina applicaziun da sfurzar autras applicaziuns da serrar."</string>
-    <!-- outdated translation 1804196839880393631 -->     <string name="permlab_forceBack" msgid="652935204072584616">"serrar l\'applicaziun cun forza"</string>
-    <!-- outdated translation 6534109744159919013 -->     <string name="permdesc_forceBack" msgid="3892295830419513623">"Permetta ad ina applicaziun da serrar tut las activitads che vegnan exequidas en il fund davant e da las spustar en il fund davos. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_killBackgroundProcesses (931129103262126617) -->
+    <skip />
+    <!-- no translation found for permlab_forceStopPackages (2329627428832067700) -->
+    <skip />
+    <!-- no translation found for permdesc_forceStopPackages (5253157296183940812) -->
+    <skip />
+    <!-- no translation found for permlab_forceBack (652935204072584616) -->
+    <skip />
+    <!-- no translation found for permdesc_forceBack (3892295830419513623) -->
+    <skip />
     <string name="permlab_dump" msgid="1681799862438954752">"verifitgar il status intern dal sistem"</string>
-    <!-- outdated translation 2198776174276275220 -->     <string name="permdesc_dump" msgid="1778299088692290329">"\"Permetta ad ina applicaziun da vesair il status intern dal sistem. Applicaziuns donnegiusas pon uschia obtegnair numerusas infurmaziuns privatas u segiradas, a las qualas ellas na dastgassan normalmain mai acceder.\""</string>
+    <!-- no translation found for permdesc_dump (1778299088692290329) -->
+    <skip />
     <!-- no translation found for permlab_retrieve_window_content (8022588608994589938) -->
     <skip />
     <!-- no translation found for permdesc_retrieve_window_content (3193269069469700265) -->
@@ -245,42 +313,62 @@
     <string name="permlab_shutdown" msgid="7185747824038909016">"serrar parzialmain"</string>
     <string name="permdesc_shutdown" msgid="7046500838746291775">"Metta l\'administratur dad activitads en in stadi da pausa. El na vegn betg serrà dal tut."</string>
     <string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar il midar tranter applicaziuns"</string>
-    <!-- outdated translation 3857886086919033794 -->     <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impedescha che l\'utilisader midia ad ina autra applicaziun."</string>
-    <!-- outdated translation 7811586187574696296 -->     <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"survegliar e controllar l\'aviar dad applicaziuns"</string>
-    <!-- outdated translation 3228701938345388092 -->     <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permetta ad ina applicaziun da survegliar e controllar l\'aviar dad activitads dal sistem. Applicaziuns donnegiusas pon uschia periclitar l\'entir sistem. Questa permissiun è mo previsa per process da svilup e mai per il diever normal dal telefonin."</string>
+    <!-- no translation found for permdesc_stopAppSwitches (8262195802582255021) -->
+    <skip />
+    <!-- no translation found for permlab_runSetActivityWatcher (892239094867182656) -->
+    <skip />
+    <!-- no translation found for permdesc_runSetActivityWatcher (6003603162578577406) -->
+    <skip />
     <string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"trametter in broadcast senza pachet"</string>
-    <!-- outdated translation 3453286591439891260 -->     <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Permetta ad ina applicaziun da trametter in avis cura ch\'in pachet d\'applicaziun è vegnì stizzà. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per interrumper l\'execuziun dad autras applicaziuns."</string>
+    <!-- no translation found for permdesc_broadcastPackageRemoved (6621901216207931089) -->
+    <skip />
     <string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"trametter in broadcast retschavì per SMS"</string>
-    <!-- outdated translation 9122419277306740155 -->     <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permetta ad ina applicaziun da trametter in avis cura ch\'in messadi vegn retschavì. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per dar da crair ch\'in messadi saja arrivà."</string>
+    <!-- no translation found for permdesc_broadcastSmsReceived (4152037720034365492) -->
+    <skip />
     <string name="permlab_broadcastWapPush" msgid="3145347413028582371">"trametter in broadcast retschavì da WAP-PUSH"</string>
-    <!-- outdated translation 3955303669461378091 -->     <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permetta ad ina applicaziun da trametter in avis cura ch\'in messadi WAP PUSH vegn retschavì. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per dar da crair ch\'in MMS saja arrivà u per remplazzar il cuntegn da mintga pagina d\'internet cun datas donnegiusas."</string>
+    <!-- no translation found for permdesc_broadcastWapPush (4783402525039442729) -->
+    <skip />
     <string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar il dumber maximal da process exequids"</string>
-    <!-- outdated translation 7824786028557379539 -->     <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permetta ad ina applicaziun da controllar il dumber maximal da process che pon vegnir exequids a medem temp. Betg previs per applicaziuns normalas."</string>
-    <!-- outdated translation 5342837862439543783 -->     <string name="permlab_setAlwaysFinish" msgid="238828158465736054">"serrar tut las applicaziuns en il fund davos"</string>
-    <!-- outdated translation 8773936403987091620 -->     <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Permetta ad ina applicaziun da controllar schebain activitads vegnan adina terminadas sch\'ellas vegnan stuschadas en il fund davos. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_setProcessLimit (7318061314040879542) -->
+    <skip />
+    <!-- no translation found for permlab_setAlwaysFinish (238828158465736054) -->
+    <skip />
+    <!-- no translation found for permdesc_setAlwaysFinish (7471310652868841499) -->
+    <skip />
     <string name="permlab_batteryStats" msgid="7863923071360031652">"modifitgar las datas da l\'accu"</string>
-    <!-- outdated translation 5847319823772230560 -->     <string name="permdesc_batteryStats" msgid="6835186932305744068">"Permetta da modifitgar las datas statisticas da l\'accu. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_batteryStats (6835186932305744068) -->
+    <skip />
     <string name="permlab_backup" msgid="470013022865453920">"controllar las copias da segirezza e la restauraziun dal sistem"</string>
-    <!-- outdated translation 4837493065154256525 -->     <string name="permdesc_backup" msgid="6912230525140589891">"Permetta a l\'applicaziun da controllar il mecanissem da copias da segirezza e da restauraziun dal sistem. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_backup (6912230525140589891) -->
+    <skip />
     <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
     <skip />
     <!-- no translation found for permdesc_confirm_full_backup (1748762171637699562) -->
     <skip />
     <string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mussar fanestras betg autorisadas"</string>
-    <!-- outdated translation 5895082268284998469 -->     <string name="permdesc_internalSystemWindow" msgid="6510907081810231374">"Permetta da crear fanestras destinadas per l\'utilisaziun da l\'interfatscha d\'utilisader interna dal sistem. Questa funcziun n\'è betg previsa per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_internalSystemWindow (7458387759461466397) -->
+    <skip />
     <string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mussar avertiments dal sistem"</string>
-    <!-- outdated translation 5109622689323490558 -->     <string name="permdesc_systemAlertWindow" msgid="8507863469978066409">"Permetta ad ina applicaziun da mussar fanestras cun avertiments dal sistem. Applicaziuns donnegiusas pon uschia occupar l\'entir visur dal telefonin."</string>
+    <!-- no translation found for permdesc_systemAlertWindow (8507863469978066409) -->
+    <skip />
     <string name="permlab_setAnimationScale" msgid="2805103241153907174">"modifitgar la sveltezza globala da las animaziuns"</string>
-    <!-- outdated translation 7181522138912391988 -->     <string name="permdesc_setAnimationScale" msgid="6505093307223395456">"Permetta ad ina applicaziun da modifitgar da tut temp la sveltezza generala da las animaziuns (per las pudair far ir pli svelt u pli plaun)."</string>
-    <!-- outdated translation 17124341698093865 -->     <string name="permlab_manageAppTokens" msgid="1286505717050121370">"administrar tokens dad applicaziuns"</string>
-    <!-- outdated translation 977127907524195988 -->     <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Permetta ad applicaziuns da crear ed administrar lur agens tokens cun ignorar lur urden da zavrar Z normal. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_setAnimationScale (7690063428924343571) -->
+    <skip />
+    <!-- no translation found for permlab_manageAppTokens (1286505717050121370) -->
+    <skip />
+    <!-- no translation found for permdesc_manageAppTokens (8043431713014395671) -->
+    <skip />
     <string name="permlab_injectEvents" msgid="1378746584023586600">"smatgar tastas e tastas da controlla"</string>
-    <!-- outdated translation 3946098050410874715 -->     <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Permetta ad ina applicaziun da furnir ses agens cumonds (tastas smatgadas etc.) ad autras applicaziuns. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per surpigliar la controlla da Voss telefonin."</string>
-    <!-- outdated translation 3946098050410874715 -->     <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Permetta ad ina applicaziun da furnir ses agens cumonds (tastas smatgadas etc.) ad autras applicaziuns. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per surpigliar la controlla da Voss telefonin."</string>
+    <!-- no translation found for permdesc_injectEvents (206352565599968632) -->
+    <skip />
+    <!-- no translation found for permdesc_injectEvents (653128057572326253) -->
+    <skip />
     <string name="permlab_readInputState" msgid="469428900041249234">"registrar endataziuns sur la tastatura ed acziuns"</string>
-    <!-- outdated translation 5132879321450325445 -->     <string name="permdesc_readInputState" msgid="8387754901688728043">"\"Permetta ad ina applicaziun dad identifitgar las tastas che Vus smatgais, era durant l\'utilisaziun dad in auter program (durant l\'endataziun dad in pled-clav, per exempel). Applicaziuns normalas na duessan betg avair access a questa funcziun.\""</string>
+    <!-- no translation found for permdesc_readInputState (8387754901688728043) -->
+    <skip />
     <string name="permlab_bindInputMethod" msgid="3360064620230515776">"associar cun ina metoda d\'endataziun"</string>
-    <!-- outdated translation 3734838321027317228 -->     <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permetta da sa fixar al nivel d\'interfatscha pli aut dad ina metoda d\'endataziun. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_bindInputMethod (3250440322807286331) -->
+    <skip />
     <!-- no translation found for permlab_bindTextService (7358378401915287938) -->
     <skip />
     <!-- no translation found for permdesc_bindTextService (8151968910973998670) -->
@@ -290,66 +378,112 @@
     <!-- no translation found for permdesc_bindVpnService (2067845564581693905) -->
     <skip />
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sa fixar vid in fund davos"</string>
-    <!-- outdated translation 5287754520361915347 -->     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permetta da sa fixar al nivel d\'interfatscha pli aut dad ina metoda d\'endataziun. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_bindWallpaper (7108428692595491668) -->
+    <skip />
     <!-- no translation found for permlab_bindRemoteViews (5697987759897367099) -->
     <skip />
     <!-- no translation found for permdesc_bindRemoteViews (4717987810137692572) -->
     <skip />
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacziun cun in administratur dad apparats"</string>
-    <!-- outdated translation 8714424333082216979 -->     <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permetta al possessur da trametter intenziuns a l\'administratur dal apparat periferic. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_bindDeviceAdmin (569715419543907930) -->
+    <skip />
     <string name="permlab_setOrientation" msgid="3365947717163866844">"midar l\'orientaziun dal visur"</string>
-    <!-- outdated translation 6335814461615851863 -->     <string name="permdesc_setOrientation" msgid="3046126619316671476">"Permetta a l\'applicaziun da midar da tut temp la orientaziun dal visur. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_setOrientation (3046126619316671476) -->
+    <skip />
     <!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
     <skip />
     <!-- no translation found for permdesc_setPointerSpeed (6866563234274104233) -->
     <skip />
-    <!-- outdated translation 4255467255488653854 -->     <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"trametter signals Linux a las applicaziuns"</string>
-    <!-- outdated translation 3565530463215015289 -->     <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permetta a l\'applicaziun da pretender ch\'il signal furnì vegnia tramess a tut ils process persistents."</string>
-    <!-- outdated translation 8659652042401085862 -->     <string name="permlab_persistentActivity" msgid="8841113627955563938">"exequir permanentamain applicaziuns"</string>
-    <!-- outdated translation 5037199778265006008 -->     <string name="permdesc_persistentActivity" msgid="4909910271316074418">"Permetta ad ina applicaziun da render persistent atgnas cumponentas per ch\'il sistem na po betg utilisar questas per autras applicaziuns."</string>
-    <!-- outdated translation 3343439331576348805 -->     <string name="permlab_deletePackages" msgid="184385129537705938">"stizzar applicaziuns"</string>
-    <!-- outdated translation 3634943677518723314 -->     <string name="permdesc_deletePackages" msgid="7411480275167205081">"Permetta ad ina applicaziun da stizzar pachets da datas Android. Applicaziuns donnegiusas pon utilisar questa funcziun per stizzar applicaziuns impurtantas."</string>
-    <!-- outdated translation 2192134353540277878 -->     <string name="permlab_clearAppUserData" msgid="274109191845842756">"stizzar datas dad ina autra applicaziun"</string>
-    <!-- outdated translation 7546345080434325456 -->     <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Permetta ad ina applicaziun da stizzar las datas da l\'utilisader."</string>
-    <!-- outdated translation 1518556602634276725 -->     <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"stizzar ils caches dad autras applicaziuns"</string>
-    <!-- outdated translation 2283074077168165971 -->     <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Permetta ad ina applicaziun da stizzar las datotecas en il cache."</string>
-    <!-- outdated translation 4799785352306641460 -->     <string name="permlab_getPackageSize" msgid="7472921768357981986">"evaluar la capacitad da memoria occupada da l\'applicaziun"</string>
-    <!-- outdated translation 5557253039670753437 -->     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"\"Permetta ad ina applicaziun dad obtegnair la grondezza dal code, da las datas e dal cache.\""</string>
-    <!-- outdated translation 335800214119051089 -->     <string name="permlab_installPackages" msgid="2199128482820306924">"installar directamain applicaziuns"</string>
-    <!-- outdated translation 526669220850066132 -->     <string name="permdesc_installPackages" msgid="5628530972548071284">"Permetta ad ina applicaziun dad installar pachets novs u actualisads dad Android. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per agiuntar novas applicaziuns che han tut las permissiuns pussaivlas."</string>
-    <!-- outdated translation 4747698311163766540 -->     <string name="permlab_clearAppCache" msgid="7487279391723526815">"stizzar las datas dal cache da tut las applicaziuns"</string>
-    <!-- outdated translation 7740465694193671402 -->     <string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Permetta ad ina applicaziun da dar liber capacitad da memorisar dal telefonin cun stizzar datotecas en l\'ordinatur da cache da l\'applicaziun. L\'access è per regla limità a process da sistem."</string>
-    <!-- outdated translation 7740465694193671402 -->     <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Permetta ad ina applicaziun da dar liber capacitad da memorisar dal telefonin cun stizzar datotecas en l\'ordinatur da cache da l\'applicaziun. L\'access è per regla limità a process da sistem."</string>
-    <!-- outdated translation 728454979946503926 -->     <string name="permlab_movePackage" msgid="3289890271645921411">"Spustar resursas d\'applicaziun"</string>
-    <!-- outdated translation 6323049291923925277 -->     <string name="permdesc_movePackage" msgid="319562217778244524">"Permetta ad ina applicaziun da spustar resursas d\'applicaziun dad in medium intern ad in medium extern e viceversa."</string>
-    <!-- outdated translation 4811921703882532070 -->     <string name="permlab_readLogs" msgid="6615778543198967614">"leger datotecas da protocol dal sistem"</string>
-    <!-- outdated translation 2257937955580475902 -->     <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Permetta ad ina applicaziun da leger las differentas datotecas da protocol dal sistem. Quai pussibilitescha dad obtegnair infurmaziuns generalas davart il diever da Voss telefon che na duessan betg cuntegnair datas persunalas u privatas."</string>
-    <!-- outdated translation 2257937955580475902 -->     <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Permetta ad ina applicaziun da leger las differentas datotecas da protocol dal sistem. Quai pussibilitescha dad obtegnair infurmaziuns generalas davart il diever da Voss telefon che na duessan betg cuntegnair datas persunalas u privatas."</string>
+    <!-- no translation found for permlab_signalPersistentProcesses (4539002991947376659) -->
+    <skip />
+    <!-- no translation found for permdesc_signalPersistentProcesses (4896992079182649141) -->
+    <skip />
+    <!-- no translation found for permlab_persistentActivity (8841113627955563938) -->
+    <skip />
+    <!-- no translation found for permdesc_persistentActivity (4909910271316074418) -->
+    <skip />
+    <!-- no translation found for permlab_deletePackages (184385129537705938) -->
+    <skip />
+    <!-- no translation found for permdesc_deletePackages (7411480275167205081) -->
+    <skip />
+    <!-- no translation found for permlab_clearAppUserData (274109191845842756) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppUserData (4625323684125459488) -->
+    <skip />
+    <!-- no translation found for permlab_deleteCacheFiles (3128665571837408675) -->
+    <skip />
+    <!-- no translation found for permdesc_deleteCacheFiles (3812998599006730196) -->
+    <skip />
+    <!-- no translation found for permlab_getPackageSize (7472921768357981986) -->
+    <skip />
+    <!-- no translation found for permdesc_getPackageSize (3921068154420738296) -->
+    <skip />
+    <!-- no translation found for permlab_installPackages (2199128482820306924) -->
+    <skip />
+    <!-- no translation found for permdesc_installPackages (5628530972548071284) -->
+    <skip />
+    <!-- no translation found for permlab_clearAppCache (7487279391723526815) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppCache (3523396284474042284) -->
+    <skip />
+    <!-- no translation found for permdesc_clearAppCache (5067988373366292186) -->
+    <skip />
+    <!-- no translation found for permlab_movePackage (3289890271645921411) -->
+    <skip />
+    <!-- no translation found for permdesc_movePackage (319562217778244524) -->
+    <skip />
+    <!-- no translation found for permlab_readLogs (6615778543198967614) -->
+    <skip />
+    <!-- no translation found for permdesc_readLogs (82061313293455151) -->
+    <skip />
+    <!-- no translation found for permdesc_readLogs (2063438140241560443) -->
+    <skip />
+    <!-- no translation found for permlab_anyCodecForPlayback (715805555823881818) -->
+    <skip />
+    <!-- no translation found for permdesc_anyCodecForPlayback (8283912488433189010) -->
+    <skip />
     <string name="permlab_diagnostic" msgid="8076743953908000342">"leger/scriver en resursas che appartegnan a diagnostics"</string>
-    <!-- outdated translation 3121238373951637049 -->     <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permetta ad ina applicaziun da leger e modifitgar tut ils elements ella gruppa da diagnosa (per exempel las datotecas en /dev). Quai po avair consequenzas negativas per la stabilitad e la segirezza dal sistem e duess vegnir permess mo a programs da diagnosa specifics per la hardware mess a disposiziun dal producider u dal gestiunari da la rait."</string>
-    <!-- outdated translation 79425198834329406 -->     <string name="permlab_changeComponentState" msgid="6335576775711095931">"activar u deactivar cumponentas dad applicaziuns"</string>
-    <!-- outdated translation 4569107043246700630 -->     <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"\"Permetta ad ina applicaziun dad activar u deactivar cumponentas dad autras applicaziuns. Applicaziuns donnegiusas pon uschia deactivar funcziuns impurtantas dal telefonin. Faschai attenziun cun permetter l\'access a questa funcziun perquai ch\'ella permetta da render nunduvrablas, incoerentas ed instabilas las cumponentas da las applicaziuns.\""</string>
-    <!-- outdated translation 4569107043246700630 -->     <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"\"Permetta ad ina applicaziun dad activar u deactivar cumponentas dad autras applicaziuns. Applicaziuns donnegiusas pon uschia deactivar funcziuns impurtantas dal telefonin. Faschai attenziun cun permetter l\'access a questa funcziun perquai ch\'ella permetta da render nunduvrablas, incoerentas ed instabilas las cumponentas da las applicaziuns.\""</string>
-    <!-- outdated translation 3393305202145172005 -->     <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"definir las applicaziuns preferidas"</string>
-    <!-- outdated translation 760008293501937546 -->     <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Permetta ad ina applicaziun da modifitgar Vossas applicaziuns preferidas. Applicaziuns donnegiusas pon uschia remplazzar en il zuppà applicaziuns che vegnan gist exequidas ed imitar Vossas applicaziuns existentas cun la finamira da rimnar datas persunalas da Vus."</string>
+    <!-- no translation found for permdesc_diagnostic (6608295692002452283) -->
+    <skip />
+    <!-- no translation found for permlab_changeComponentState (6335576775711095931) -->
+    <skip />
+    <!-- no translation found for permdesc_changeComponentState (8887435740982237294) -->
+    <skip />
+    <!-- no translation found for permdesc_changeComponentState (1827232484416505615) -->
+    <skip />
+    <!-- no translation found for permlab_setPreferredApplications (8463181628695396391) -->
+    <skip />
+    <!-- no translation found for permdesc_setPreferredApplications (4973986762241783712) -->
+    <skip />
     <string name="permlab_writeSettings" msgid="1365523497395143704">"modifitgar parameters generals dal sistem"</string>
-    <!-- outdated translation 838789419871034696 -->     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Permetta ad ina applicaziun da modifitgar las datas dals parameters dal sistem. Applicaziuns donnegiusas pon utilisar questa funcziun per donnegiar la configuraziun da Voss sistem."</string>
+    <!-- no translation found for permdesc_writeSettings (7775723441558907181) -->
+    <skip />
     <string name="permlab_writeSecureSettings" msgid="204676251876718288">"modifitgar ils parameters da segirezza dal sistem"</string>
-    <!-- outdated translation 5497873143539034724 -->     <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Permetta ad ina applicaziun da modifitgar las datas da configuraziun da segirezza dal sistem. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_writeSecureSettings (8159535613020137391) -->
+    <skip />
     <string name="permlab_writeGservices" msgid="2149426664226152185">"modifitgar Google Services Map"</string>
-    <!-- outdated translation 6602362746516676175 -->     <string name="permdesc_writeGservices" msgid="1287309437638380229">"Permetta ad ina applicaziun da modifitgar la charta da servetschs Google. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_writeGservices (1287309437638380229) -->
+    <skip />
     <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"aviar automaticamain suenter ch\'il sistem è avià"</string>
-    <!-- outdated translation 698336728415008796 -->     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"\"Permetta ad ina applicaziun dad aviar sasez suenter ch\'il sistem è vegnì avià. Qua tras po l\'aviar dal telefonin durar pli ditg, ultra da quai po l\'entir sistem vegnir retardà cun l\'activitad permanenta da l\'applicaziun.\""</string>
-    <!-- outdated translation 698336728415008796 -->     <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"\"Permetta ad ina applicaziun dad aviar sasez suenter ch\'il sistem è vegnì avià. Qua tras po l\'aviar dal telefonin durar pli ditg, ultra da quai po l\'entir sistem vegnir retardà cun l\'activitad permanenta da l\'applicaziun.\""</string>
+    <!-- no translation found for permdesc_receiveBootCompleted (7390304664116880704) -->
+    <skip />
+    <!-- no translation found for permdesc_receiveBootCompleted (513950589102617504) -->
+    <skip />
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"trametter in broadcast permanent"</string>
-    <!-- outdated translation 1920045289234052219 -->     <string name="permdesc_broadcastSticky" product="tablet" msgid="1181582512022829259">"Permetta ad ina applicaziun da trametter broadcasts persistents che na sa serran betg a la fin dal broadcast. Applicaziuns donnegiusas pon uschia render plaun ed instabil il telefonin cun occupar memia blera memoria."</string>
-    <!-- outdated translation 1920045289234052219 -->     <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Permetta ad ina applicaziun da trametter broadcasts persistents che na sa serran betg a la fin dal broadcast. Applicaziuns donnegiusas pon uschia render plaun ed instabil il telefonin cun occupar memia blera memoria."</string>
+    <!-- no translation found for permdesc_broadcastSticky (1181582512022829259) -->
+    <skip />
+    <!-- no translation found for permdesc_broadcastSticky (3287869131621514325) -->
+    <skip />
     <string name="permlab_readContacts" msgid="6219652189510218240">"leger las datas da contact"</string>
-    <!-- outdated translation 3371591512896545975 -->     <string name="permdesc_readContacts" product="tablet" msgid="4028657556924039119">"Permetta ad ina applicaziun da leger tut las datas da contacts (adressas) memorisadas sin Voss telefonin. Applicaziuns donnegiusas pon utilisar questa funcziun per trametter Vossas datas ad autras persunas."</string>
-    <!-- outdated translation 3371591512896545975 -->     <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Permetta ad ina applicaziun da leger tut las datas da contacts (adressas) memorisadas sin Voss telefonin. Applicaziuns donnegiusas pon utilisar questa funcziun per trametter Vossas datas ad autras persunas."</string>
+    <!-- no translation found for permdesc_readContacts (4028657556924039119) -->
+    <skip />
+    <!-- no translation found for permdesc_readContacts (2032222056456498547) -->
+    <skip />
     <string name="permlab_writeContacts" msgid="644616215860933284">"scriver datas da contact"</string>
-    <!-- outdated translation 3924383579108183601 -->     <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Permetta ad ina applicaziun da modifitgar tut las datas da contact (adressas) memorisadas sin Voss telefonin. Applicaziuns donnegiusas pon utilisar questa funcziun per stizzar u modifitgar Vossas datas da contact."</string>
-    <!-- outdated translation 3924383579108183601 -->     <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Permetta ad ina applicaziun da modifitgar tut las datas da contact (adressas) memorisadas sin Voss telefonin. Applicaziuns donnegiusas pon utilisar questa funcziun per stizzar u modifitgar Vossas datas da contact."</string>
+    <!-- no translation found for permdesc_writeContacts (988969759110632978) -->
+    <skip />
+    <!-- no translation found for permdesc_writeContacts (5075164818647934067) -->
+    <skip />
     <!-- no translation found for permlab_readProfile (6824681438529842282) -->
     <skip />
     <!-- no translation found for permdesc_readProfile (94520753797630679) -->
@@ -366,59 +500,96 @@
     <skip />
     <!-- no translation found for permdesc_writeSocialStream (3496277176955721451) -->
     <skip />
-    <!-- outdated translation 6898987798303840534 -->     <string name="permlab_readCalendar" msgid="5972727560257612398">"leger eveniments da chalender"</string>
-    <!-- outdated translation 5533029139652095734 -->     <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Permetta ad ina applicaziun da leger tut ils eveniments da chalender memorisads sin Voss telefonin. Applicaziuns donnegiusas pon uschia trametter Voss eveniments da chalender ad autras persunas."</string>
-    <!-- outdated translation 5533029139652095734 -->     <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Permetta ad ina applicaziun da leger tut ils eveniments da chalender memorisads sin Voss telefonin. Applicaziuns donnegiusas pon uschia trametter Voss eveniments da chalender ad autras persunas."</string>
-    <!-- outdated translation 3894879352594904361 -->     <string name="permlab_writeCalendar" msgid="8438874755193825647">"agiuntar u modifitgar eveniments en il chalender e trametter e-mails als envidads"</string>
-    <!-- outdated translation 2988871373544154221 -->     <string name="permdesc_writeCalendar" msgid="2243771395254848873">"Permetta ad ina applicaziun dad agiuntar u modifitgar eveniments en Voss chalender che pon trametter e-mails ad envidads. Applicaziuns donnegiusas pon uschia stizzar u modifitgar las datas en Voss chalender u trametter e-mails ad envidads."</string>
+    <!-- no translation found for permlab_readCalendar (5972727560257612398) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (2338414551004122687) -->
+    <skip />
+    <!-- no translation found for permdesc_readCalendar (5693933067751827753) -->
+    <skip />
+    <!-- no translation found for permlab_writeCalendar (8438874755193825647) -->
+    <skip />
+    <!-- no translation found for permdesc_writeCalendar (2243771395254848873) -->
+    <skip />
     <string name="permlab_accessMockLocation" msgid="8688334974036823330">"creaziun da funtaunas da posiziun fictivas per motivs da test"</string>
-    <!-- outdated translation 7648286063459727252 -->     <string name="permdesc_accessMockLocation" msgid="7577931556422993949">"Permetta da crear funtaunas da localisaziun fictivas per motivs da test. Applicaziuns donnegiusas pon uschia remplazzar la posiziun ed il status returnà da las vairas funtaunas sco GPS u Voss gestiunari da la rait."</string>
+    <!-- no translation found for permdesc_accessMockLocation (7577931556422993949) -->
+    <skip />
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"access als cumonds supplementars da purschiders da posiziuns geograficas"</string>
-    <!-- outdated translation 1948144701382451721 -->     <string name="permdesc_accessLocationExtraCommands" msgid="6737736970602176133">"Permetta d\'acceder a cumonds supplementars da purschiders da posiziuns geograficas. Applicaziuns donnegiusas pon uschia eventualmain disturbar il funcziunament da GPS u autras funtaunas da localisaziun geografica."</string>
+    <!-- no translation found for permdesc_accessLocationExtraCommands (6737736970602176133) -->
+    <skip />
     <string name="permlab_installLocationProvider" msgid="6578101199825193873">"permetter l\'installaziun d\'in purschider da servetschs da localisaziun"</string>
-    <!-- outdated translation 5449175116732002106 -->     <string name="permdesc_installLocationProvider" msgid="1742577679350078373">"Crear funtaunas da localisaziun fictivas per motivs da test. Applicaziuns donnegiusas pon uschia remplazzar la posiziun ed il status returnads da las funtaunas vairas sco GPS u Voss gestiunari da la rait u survegliar Vossa posiziun geografica e la transmetter ad ina funtauna externa."</string>
+    <!-- no translation found for permdesc_installLocationProvider (1742577679350078373) -->
+    <skip />
     <string name="permlab_accessFineLocation" msgid="8116127007541369477">"posiziun exacta (GPS)"</string>
-    <!-- outdated translation 7411213317434337331 -->     <string name="permdesc_accessFineLocation" product="tablet" msgid="5326423948268164934">"Permetta d\'acceder a funtaunas da localisaziun exactas sco GPS (Global Positioning System) sche in tal è disponibel. Applicaziuns donnegiusas pon uschia identifitgar Vossa posiziun geografica e consumar energia supplementara da l\'accu."</string>
-    <!-- outdated translation 7411213317434337331 -->     <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Permetta d\'acceder a funtaunas da localisaziun exactas sco GPS (Global Positioning System) sche in tal è disponibel. Applicaziuns donnegiusas pon uschia identifitgar Vossa posiziun geografica e consumar energia supplementara da l\'accu."</string>
+    <!-- no translation found for permdesc_accessFineLocation (5326423948268164934) -->
+    <skip />
+    <!-- no translation found for permdesc_accessFineLocation (7130267914433890869) -->
+    <skip />
     <string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"Posiziun geografica approximativa (sin basa da la rait)"</string>
-    <!-- outdated translation 8235655958070862293 -->     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="5460726396318105483">"\"Acceda a funtaunas approximativas da localisaziun (per exempel bancas da datas da raits mobilas) per determinar la posiziun geografica dal telefonin, sche questa opziun è disponibla. Applicaziuns donnegiusas pon utilisar questa funcziun per vegnir a savair nua che Vus sa chattais circa.\""</string>
-    <!-- outdated translation 8235655958070862293 -->     <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"\"Acceda a funtaunas approximativas da localisaziun (per exempel bancas da datas da raits mobilas) per determinar la posiziun geografica dal telefonin, sche questa opziun è disponibla. Applicaziuns donnegiusas pon utilisar questa funcziun per vegnir a savair nua che Vus sa chattais circa.\""</string>
+    <!-- no translation found for permdesc_accessCoarseLocation (5460726396318105483) -->
+    <skip />
+    <!-- no translation found for permdesc_accessCoarseLocation (8900795778057579522) -->
+    <skip />
     <string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"access a SurfaceFlinger"</string>
-    <!-- outdated translation 6805241830020733025 -->     <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permetta ad ina applicaziun dad utilisar las funcziuns SurfaceFlinger datiers al nivel dal sistem."</string>
+    <!-- no translation found for permdesc_accessSurfaceFlinger (1041619516733293551) -->
+    <skip />
     <string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leger il paraculp da frame"</string>
-    <!-- outdated translation 5777679658669057819 -->     <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permetta ad ina applicaziun da leger il cuntegn dal paraculp da frame."</string>
+    <!-- no translation found for permdesc_readFrameBuffer (4937405521809454680) -->
+    <skip />
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifitgar Voss parameters audio"</string>
-    <!-- outdated translation 5793461287365991922 -->     <string name="permdesc_modifyAudioSettings" msgid="7343951185408396919">"Permetta a l\'applicaziun da modifitgar ils parameters generals dad audio (per exempel il volumen e routing)."</string>
+    <!-- no translation found for permdesc_modifyAudioSettings (7343951185408396919) -->
+    <skip />
     <string name="permlab_recordAudio" msgid="3876049771427466323">"registrar audio"</string>
-    <!-- outdated translation 6493228261176552356 -->     <string name="permdesc_recordAudio" msgid="2387462233976248635">"Permetta a l\'applicaziun dad acceder a la via d\'access per registraziuns dad audio."</string>
+    <!-- no translation found for permdesc_recordAudio (2387462233976248635) -->
+    <skip />
     <string name="permlab_camera" msgid="3616391919559751192">"fotografar e registrar videos"</string>
-    <!-- outdated translation 6004878235852154239 -->     <string name="permdesc_camera" msgid="1507407407002492176">"Permetta a l\'applicaziun da fotografar e da registrar videos cun la camera. Uschia po l\'applicaziun rimnar da tut temp maletgs fatgs cun la camera."</string>
-    <!-- outdated translation 8337817093326370537 -->     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"deactivar permanentamain il telefonin"</string>
+    <!-- no translation found for permdesc_camera (1507407407002492176) -->
+    <skip />
+    <!-- no translation found for permlab_brick (2961292205764488304) -->
+    <skip />
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"deactivar permanentamain il telefonin"</string>
-    <!-- outdated translation 5569526552607599221 -->     <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Permetta ad ina applicaziun da deactivar definitivamain il telefon. Questa autorisaziun è fitg privlusa."</string>
-    <!-- outdated translation 5569526552607599221 -->     <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Permetta ad ina applicaziun da deactivar definitivamain il telefon. Questa autorisaziun è fitg privlusa."</string>
-    <!-- outdated translation 2898560872462638242 -->     <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"sfurzar il telefonin da reaviar"</string>
+    <!-- no translation found for permdesc_brick (4334818808001699530) -->
+    <skip />
+    <!-- no translation found for permdesc_brick (5788903297627283099) -->
+    <skip />
+    <!-- no translation found for permlab_reboot (3436634972561795002) -->
+    <skip />
     <string name="permlab_reboot" product="default" msgid="2898560872462638242">"sfurzar il telefonin da reaviar"</string>
-    <!-- outdated translation 7914933292815491782 -->     <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"Permetta a l\'applicaziun da sfurzar il telefonin da reaviar."</string>
-    <!-- outdated translation 7914933292815491782 -->     <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Permetta a l\'applicaziun da sfurzar il telefonin da reaviar."</string>
+    <!-- no translation found for permdesc_reboot (8172056180063700741) -->
+    <skip />
+    <!-- no translation found for permdesc_reboot (5326008124289989969) -->
+    <skip />
     <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar e demontar sistems da datotecas"</string>
-    <!-- outdated translation 6253263792535859767 -->     <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"Permetta a l\'applicaziun da montar e demontar sistems da datotecas per apparats periferics da memoria mobila."</string>
+    <!-- no translation found for permdesc_mount_unmount_filesystems (1829290701658992347) -->
+    <skip />
     <string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formataziun da la memoria externa"</string>
-    <!-- outdated translation 574060044906047386 -->     <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"Permetta a l\'applicaziun da formatar memoria mobila."</string>
-    <!-- outdated translation 1070364079249834666 -->     <string name="permlab_asec_access" msgid="3411338632002193846">"obtegnair infurmaziuns davart la memoria segira"</string>
-    <!-- outdated translation 7691616292170590244 -->     <string name="permdesc_asec_access" msgid="3094563844593878548">"Permetta a l\'applicaziun dad obtegnair infurmaziuns davart la memoria segira."</string>
-    <!-- outdated translation 7312078032326928899 -->     <string name="permlab_asec_create" msgid="6414757234789336327">"crear ina memoria segira"</string>
-    <!-- outdated translation 7041802322759014035 -->     <string name="permdesc_asec_create" msgid="4558869273585856876">"Permetta a l\'applicaziun da crear ina memoria segira."</string>
-    <!-- outdated translation 7787322878955261006 -->     <string name="permlab_asec_destroy" msgid="526928328301618022">"allontanar la memoria segira"</string>
-    <!-- outdated translation 5740754114967893169 -->     <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Permetta a l\'applicaziun dad allontanar la memoria segira."</string>
-    <!-- outdated translation 7517449694667828592 -->     <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"montar/demontar la memoria segira"</string>
-    <!-- outdated translation 5438078121718738625 -->     <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Permetta a l\'applicaziun da montar/demontar la memoria segira."</string>
-    <!-- outdated translation 5685344390439934495 -->     <string name="permlab_asec_rename" msgid="7496633954080472417">"renumnar la memoria segira"</string>
-    <!-- outdated translation 1387881770708872470 -->     <string name="permdesc_asec_rename" msgid="1794757588472127675">"Permetta a l\'applicaziun da renumnar la memoria segira."</string>
+    <!-- no translation found for permdesc_mount_format_filesystems (8784268246779198627) -->
+    <skip />
+    <!-- no translation found for permlab_asec_access (3411338632002193846) -->
+    <skip />
+    <!-- no translation found for permdesc_asec_access (3094563844593878548) -->
+    <skip />
+    <!-- no translation found for permlab_asec_create (6414757234789336327) -->
+    <skip />
+    <!-- no translation found for permdesc_asec_create (4558869273585856876) -->
+    <skip />
+    <!-- no translation found for permlab_asec_destroy (526928328301618022) -->
+    <skip />
+    <!-- no translation found for permdesc_asec_destroy (7218749286145526537) -->
+    <skip />
+    <!-- no translation found for permlab_asec_mount_unmount (8877998101944999386) -->
+    <skip />
+    <!-- no translation found for permdesc_asec_mount_unmount (3451360114902490929) -->
+    <skip />
+    <!-- no translation found for permlab_asec_rename (7496633954080472417) -->
+    <skip />
+    <!-- no translation found for permdesc_asec_rename (1794757588472127675) -->
+    <skip />
     <string name="permlab_vibrate" msgid="7768356019980849603">"controllar la vibraziun"</string>
-    <!-- outdated translation 2886677177257789187 -->     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permetta a l\'applicaziun da controllar la vibraziun."</string>
+    <!-- no translation found for permdesc_vibrate (6284989245902300945) -->
+    <skip />
     <string name="permlab_flashlight" msgid="2155920810121984215">"controllar la glischina"</string>
-    <!-- outdated translation 6433045942283802309 -->     <string name="permdesc_flashlight" msgid="6522284794568368310">"Permetta a l\'applicaziun da controllar la glischina."</string>
+    <!-- no translation found for permdesc_flashlight (6522284794568368310) -->
+    <skip />
     <!-- no translation found for permlab_manageUsb (1113453430645402723) -->
     <skip />
     <!-- no translation found for permdesc_manageUsb (7776155430218239833) -->
@@ -428,112 +599,180 @@
     <!-- no translation found for permdesc_accessMtp (6532961200486791570) -->
     <skip />
     <string name="permlab_hardware_test" msgid="4148290860400659146">"testar la hardware"</string>
-    <!-- outdated translation 3668894686500081699 -->     <string name="permdesc_hardware_test" msgid="6597964191208016605">"Permetta ad ina applicaziun da controllar differents apparats periferics per motivs da test da hardware."</string>
+    <!-- no translation found for permdesc_hardware_test (6597964191208016605) -->
+    <skip />
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefonar directamain a numers da telefon"</string>
-    <!-- outdated translation 3369867353692722456 -->     <string name="permdesc_callPhone" msgid="6396463004110544744">"Permetta a l\'applicaziun da far telefons senza Vossa intervenziun. Applicaziuns donnegiusas pon uschia chaschunar telefons nunspetgads sin Voss quint da telefon. Questa funcziun permetta dentant betg da telefonar a numers d\'urgenza."</string>
+    <!-- no translation found for permdesc_callPhone (6396463004110544744) -->
+    <skip />
     <string name="permlab_callPrivileged" msgid="4198349211108497879">"telefonar directamain a mintga numer"</string>
-    <!-- outdated translation 244405067160028452 -->     <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Permetta a l\'applicaziun da cumponer mintga numer (inclus numers d\'urgenza) senza Vossa intervenziun. Applicaziuns donnegiusas pon uschia far telefons nunnecessaris ed illegals a numers d\'urgenza."</string>
-    <!-- outdated translation 5604848095315421425 -->     <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"aviar directamain la configuraziun dal telefonin CDMA"</string>
+    <!-- no translation found for permdesc_callPrivileged (1689024901509996810) -->
+    <skip />
+    <!-- no translation found for permlab_performCdmaProvisioning (4842576994144604821) -->
+    <skip />
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"aviar directamain la configuraziun dal telefonin CDMA"</string>
-    <!-- outdated translation 6457447676108355905 -->     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permetta a l\'applicaziun dad aviar il provediment CDMA. Applicaziuns donnegiusas pon uschia aviar inutilmain il provediment CDMA."</string>
+    <!-- no translation found for permdesc_performCdmaProvisioning (1994193538802314186) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controllar ils avis ad actualisaziuns da la posiziun geografica"</string>
-    <!-- outdated translation 2300018303720930256 -->     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permetta l\'activaziun/deactivaziun dad avis ad actualisaziuns da la posiziun geografica che derivan dal signal da radio. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_locationUpdates (1120741557891438876) -->
+    <skip />
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"access a las caracteristicas check-in"</string>
-    <!-- outdated translation 7150307006141883832 -->     <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Permetta l\'access (leger e scriver) ad elements transmess dal servetsch check-in. Betg previs per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_checkinProperties (4024526968630194128) -->
+    <skip />
     <string name="permlab_bindGadget" msgid="776905339015863471">"tscherner ils widgets"</string>
-    <!-- outdated translation 2098697834497452046 -->     <string name="permdesc_bindGadget" msgid="8261326938599049290">"Permetta a l\'applicaziun dad annunziar al sistem tge widgets che pon vegnir utilisads da tge applicaziun. Cun questa permissiun pon applicaziuns autorisar l\'access a datas persunalas per autras applicaziuns. Questa opziun n\'è betg previsa per applicaziuns normalas."</string>
+    <!-- no translation found for permdesc_bindGadget (8261326938599049290) -->
+    <skip />
     <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modifitgar il status dal telefon"</string>
-    <!-- outdated translation 3302284561346956587 -->     <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"\"Permetta ad ina applicaziun da controllar las funcziunalitads telefonicas da l\'apparat. Ina applicaziun po uschia midar la rait, deactivar ed activar il signal radiofonic dal telefon etc. senza As avertir.\""</string>
+    <!-- no translation found for permdesc_modifyPhoneState (1029877529007686732) -->
+    <skip />
     <string name="permlab_readPhoneState" msgid="2326172951448691631">"leger il status e l\'identitad dal telefon"</string>
-    <!-- outdated translation 8987653603298258459 -->     <string name="permdesc_readPhoneState" msgid="5127767618743602782">"\"Permetta a l\'applicaziun dad acceder a las funcziuns da clom dal telefonin. Ina applicaziun cun questas permissiuns po eruir il numer che quest telefonin utilisescha, schebain i vegn telefonà ed identifitgar il numer clamà etc.\""</string>
-    <!-- outdated translation 573480187941496130 -->     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar ch\'il telefon midia en il modus stand-by"</string>
+    <!-- no translation found for permdesc_readPhoneState (5127767618743602782) -->
+    <skip />
+    <!-- no translation found for permlab_wakeLock (1531731435011495015) -->
+    <skip />
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar ch\'il telefon midia en il modus stand-by"</string>
-    <!-- outdated translation 7584036471227467099 -->     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permetta ad ina applicaziun dad evitar ch\'il telefon midia en il modus standby."</string>
-    <!-- outdated translation 7584036471227467099 -->     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permetta ad ina applicaziun dad evitar ch\'il telefon midia en il modus standby."</string>
-    <!-- outdated translation 4928622470980943206 -->     <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"metter en/ord funcziun l\'apparat"</string>
+    <!-- no translation found for permdesc_wakeLock (7311319824400447868) -->
+    <skip />
+    <!-- no translation found for permdesc_wakeLock (8559100677372928754) -->
+    <skip />
+    <!-- no translation found for permlab_devicePower (2787034722616350417) -->
+    <skip />
     <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"metter en/ord funcziun l\'apparat"</string>
-    <!-- outdated translation 4577331933252444818 -->     <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permetta ad ina applicaziun dad activar u deactivar il telefonin."</string>
-    <!-- outdated translation 4577331933252444818 -->     <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Permetta ad ina applicaziun dad activar u deactivar il telefonin."</string>
+    <!-- no translation found for permdesc_devicePower (6689862878984631831) -->
+    <skip />
+    <!-- no translation found for permdesc_devicePower (6037057348463131032) -->
+    <skip />
     <string name="permlab_factoryTest" msgid="3715225492696416187">"exequir en il modus da test da fabrica"</string>
-    <!-- outdated translation 8136644990319244802 -->     <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Permetta d\'exequir sco test da fabrica datiers al nivel dal sistem cun autorisar l\'access a la hardware dal telefonin. Questa funcziunalitad è mo disponibla sch\'il telefonin sa chatta en il modus da test da fabrica."</string>
+    <!-- no translation found for permdesc_factoryTest (3952059318359653091) -->
+    <skip />
     <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Permetta d\'exequir sco test da fabrica datiers al nivel dal sistem cun autorisar l\'access a la hardware dal telefonin. Questa funcziunalitad è mo disponibla sch\'il telefonin sa chatta en il modus da test da fabrica."</string>
     <string name="permlab_setWallpaper" msgid="6627192333373465143">"definir la culissa"</string>
-    <!-- outdated translation 6417041752170585837 -->     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Permetta a l\'applicaziun da definir il fund davos dal sistem."</string>
+    <!-- no translation found for permdesc_setWallpaper (7373447920977624745) -->
+    <skip />
     <string name="permlab_setWallpaperHints" msgid="3600721069353106851">"definir ils indicaturs da grondezza per il fund davos"</string>
-    <!-- outdated translation 6019479164008079626 -->     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Permetta a l\'applicaziun da definir la grondezza dal fund dal visur."</string>
+    <!-- no translation found for permdesc_setWallpaperHints (8235784384223730091) -->
+    <skip />
     <string name="permlab_masterClear" msgid="2315750423139697397">"reinizialisar il sistem cun ses parameters originals"</string>
-    <!-- outdated translation 5033465107545174514 -->     <string name="permdesc_masterClear" msgid="3665380492633910226">"\"Permetta ad ina applicaziun da restaurar il stadi original dal sistem. Qua tras vegnan tut las datas, las configuraziuns e las applicaziuns installadas stizzadas.\""</string>
+    <!-- no translation found for permdesc_masterClear (3665380492633910226) -->
+    <skip />
     <string name="permlab_setTime" msgid="2021614829591775646">"drizzar l\'ura"</string>
-    <!-- outdated translation 667294309287080045 -->     <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Permetta ad ina applicaziun da drizzar l\'ura dal telefonin."</string>
-    <!-- outdated translation 667294309287080045 -->     <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Permetta ad ina applicaziun da drizzar l\'ura dal telefonin."</string>
+    <!-- no translation found for permdesc_setTime (1896341438151152881) -->
+    <skip />
+    <!-- no translation found for permdesc_setTime (1855702730738020) -->
+    <skip />
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"definir la zona d\'urari"</string>
-    <!-- outdated translation 1902540227418179364 -->     <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Permetta ad ina applicaziun da modifitgar la zona d\'urari dal telefonin."</string>
-    <!-- outdated translation 1902540227418179364 -->     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Permetta ad ina applicaziun da modifitgar la zona d\'urari dal telefonin."</string>
+    <!-- no translation found for permdesc_setTimeZone (1676983712315827645) -->
+    <skip />
+    <!-- no translation found for permdesc_setTimeZone (4499943488436633398) -->
+    <skip />
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"agir sco administratur da contos"</string>
-    <!-- outdated translation 6056903274106394752 -->     <string name="permdesc_accountManagerService" msgid="2684502137670299915">"Permetta ad ina applicaziun da telefonar ad autentificaturs da contos."</string>
+    <!-- no translation found for permdesc_accountManagerService (1948455552333615954) -->
+    <skip />
     <string name="permlab_getAccounts" msgid="4549918644233460103">"tschertgar contos enconuschents"</string>
-    <!-- outdated translation 6839262446413155394 -->     <string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Permetta ad ina applicaziun da consultar la glista dals contos enconuschents al telefonin."</string>
-    <!-- outdated translation 6839262446413155394 -->     <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Permetta ad ina applicaziun da consultar la glista dals contos enconuschents al telefonin."</string>
+    <!-- no translation found for permdesc_getAccounts (3238360555257773358) -->
+    <skip />
+    <!-- no translation found for permdesc_getAccounts (2735689364629830348) -->
+    <skip />
     <string name="permlab_authenticateAccounts" msgid="3940505577982882450">"agir sco autentificatur da contos"</string>
-    <!-- outdated translation 4006839406474208874 -->     <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"\"Permetta ad ina applicaziun dad utilisar las funcziuns d\'autentificaziun da conto da l\'administratur da contos, inclus funcziuns per crear contos ed obtegnair e definir lur pleds-clav.\""</string>
+    <!-- no translation found for permdesc_authenticateAccounts (5472124296908977260) -->
+    <skip />
     <string name="permlab_manageAccounts" msgid="4440380488312204365">"administrar la glista da contos"</string>
-    <!-- outdated translation 8804114016661104517 -->     <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Permetta ad ina applicaziun dad agiuntar ed allontanar contos e stizzar lur pleds-clav."</string>
+    <!-- no translation found for permdesc_manageAccounts (8698295625488292506) -->
+    <skip />
     <string name="permlab_useCredentials" msgid="6401886092818819856">"utilisar las infurmaziuns dad autentificaziun dad in conto"</string>
-    <!-- outdated translation 7416570544619546974 -->     <string name="permdesc_useCredentials" msgid="7984227147403346422">"Permetta ad ina applicaziun da dumandar tokens d\'autentificaziun."</string>
+    <!-- no translation found for permdesc_useCredentials (7984227147403346422) -->
+    <skip />
     <string name="permlab_accessNetworkState" msgid="6865575199464405769">"mussar il status da la rait"</string>
-    <!-- outdated translation 558721128707712766 -->     <string name="permdesc_accessNetworkState" msgid="479772796952547198">"Permetta ad ina applicaziun da vesair ils status da tut las raits."</string>
+    <!-- no translation found for permdesc_accessNetworkState (479772796952547198) -->
+    <skip />
     <string name="permlab_createNetworkSockets" msgid="9121633680349549585">"access cumplet a l\'internet"</string>
-    <!-- outdated translation 4593339106921772192 -->     <string name="permdesc_createNetworkSockets" msgid="5963922297444265950">"Permetta ad ina applicaziun da crear sockets da rait."</string>
-    <!-- outdated translation 7823599210086622545 -->     <string name="permlab_writeApnSettings" msgid="505660159675751896">"scriver parameters per nums da puncts d\'access"</string>
-    <!-- outdated translation 7443433457842966680 -->     <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"\"Permetta ad ina applicaziun da modifitgar ils parameters APN (num dals puncts d\'access), sco proxy ni port da mintga APN.\""</string>
+    <!-- no translation found for permdesc_createNetworkSockets (5963922297444265950) -->
+    <skip />
+    <!-- no translation found for permlab_writeApnSettings (505660159675751896) -->
+    <skip />
+    <!-- no translation found for permdesc_writeApnSettings (5333798886412714193) -->
+    <skip />
     <string name="permlab_changeNetworkState" msgid="958884291454327309">"modifitgar la connectivitad da la rait"</string>
-    <!-- outdated translation 4199958910396387075 -->     <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Permetta ad ina applicaziun da modifitgar il status da connectivitad da la rait."</string>
-    <!-- outdated translation 2702121155761140799 -->     <string name="permlab_changeTetherState" msgid="5952584964373017960">"midar la connectivitad da tethering"</string>
-    <!-- outdated translation 8905815579146349568 -->     <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permetta ad ina applicaziun da modifitgar il status da connectivitad dal tethering."</string>
+    <!-- no translation found for permdesc_changeNetworkState (6789123912476416214) -->
+    <skip />
+    <!-- no translation found for permlab_changeTetherState (5952584964373017960) -->
+    <skip />
+    <!-- no translation found for permdesc_changeTetherState (1524441344412319780) -->
+    <skip />
     <string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"modifitgar il parameter d\'utilisaziun da datas dal fund davos"</string>
-    <!-- outdated translation 1001482853266638864 -->     <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Permetta ad ina applicaziun da modifitgar il parameters d\'utilisaziun da las datas dal fund davos."</string>
+    <!-- no translation found for permdesc_changeBackgroundDataSetting (5347729578468744379) -->
+    <skip />
     <string name="permlab_accessWifiState" msgid="8100926650211034400">"mussar il status WLAN"</string>
-    <!-- outdated translation 485796529139236346 -->     <string name="permdesc_accessWifiState" msgid="7770452658226256831">"Permetta ad ina applicaziun da vesair las infurmaziuns concernent il status WLAN."</string>
+    <!-- no translation found for permdesc_accessWifiState (7770452658226256831) -->
+    <skip />
     <string name="permlab_changeWifiState" msgid="7280632711057112137">"modifitgar il status WLAN"</string>
-    <!-- outdated translation 2950383153656873267 -->     <string name="permdesc_changeWifiState" msgid="7399961004537946240">"\"Permetta ad ina applicaziun da stabilir ina connexiun a puncts d\'access WLAN, da sa deconnectar da quels e da modifitgar ils parameters da raits WLAN configuradas.\""</string>
+    <!-- no translation found for permdesc_changeWifiState (7399961004537946240) -->
+    <skip />
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permetter la recepziun da multicast WLAN"</string>
-    <!-- outdated translation 8199464507656067553 -->     <string name="permdesc_changeWifiMulticastState" msgid="7633598524564320817">"Permetta ad ina applicaziun da retschaiver pachets da datas che n\'èn betg adressads directamain a Voss apparat. Quai po esser nizzaivel per tschertgar servetschs che vegnan mess a disposiziun en il conturn. Consumescha dapli energia ch\'il modus betg-multicast."</string>
-    <!-- outdated translation 1092209628459341292 -->     <string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"administraziun bluetooth"</string>
-    <!-- outdated translation 7256289774667054555 -->     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"\"Permetta ad ina applicaziun da configurar il telefon bluetooth local, dad identifitgar apparats periferics a distanza e d\'als associar cun il telefon.\""</string>
-    <!-- outdated translation 7256289774667054555 -->     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"\"Permetta ad ina applicaziun da configurar il telefon bluetooth local, dad identifitgar apparats periferics a distanza e d\'als associar cun il telefon.\""</string>
+    <!-- no translation found for permdesc_changeWifiMulticastState (7633598524564320817) -->
+    <skip />
+    <!-- no translation found for permlab_bluetoothAdmin (3606576270792236062) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (6921177471748882137) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetoothAdmin (8931682159331542137) -->
+    <skip />
+    <!-- no translation found for permlab_accessWimaxState (1232061307208861588) -->
+    <skip />
+    <!-- no translation found for permdesc_accessWimaxState (5914958077555177749) -->
+    <skip />
+    <!-- no translation found for permlab_changeWimaxState (2405042267131496579) -->
+    <skip />
+    <!-- no translation found for permdesc_changeWimaxState (3328853825006455912) -->
+    <skip />
     <string name="permlab_bluetooth" msgid="8361038707857018732">"stabilir connexiuns bluetooth"</string>
-    <!-- outdated translation 762515380679392945 -->     <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Permetta ad ina applicaziun dad obtegnair la configuraziun dal telefon bluetooth local e da crear ed acceptar connexiuns ad apparats associads."</string>
-    <!-- outdated translation 762515380679392945 -->     <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Permetta ad ina applicaziun dad obtegnair la configuraziun dal telefon bluetooth local e da crear ed acceptar connexiuns ad apparats associads."</string>
+    <!-- no translation found for permdesc_bluetooth (7007851048416363446) -->
+    <skip />
+    <!-- no translation found for permdesc_bluetooth (31846362767164948) -->
+    <skip />
     <!-- no translation found for permlab_nfc (4423351274757876953) -->
     <skip />
     <!-- no translation found for permdesc_nfc (7120611819401789907) -->
     <skip />
     <string name="permlab_disableKeyguard" msgid="4977406164311535092">"deactivar la bloccaziun da la tastatura"</string>
-    <!-- outdated translation 3189763479326302017 -->     <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Permetta ad ina applicaziun da deactivar la bloccaziun da la tastatura e la protecziun cun il pled-clav associada. In exempel dad ina utilisaziun legitima: La bloccaziun da la tastatura vegn deactivada sche Vus retschavais in clom ed ella vegn reactivada sche Vus finis il telefon."</string>
+    <!-- no translation found for permdesc_disableKeyguard (6231611286892232626) -->
+    <skip />
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"leger ils parameters da sincronisaziun"</string>
-    <!-- outdated translation 5315925706353341823 -->     <string name="permdesc_readSyncSettings" msgid="5464056785274229278">"Permetta ad ina applicaziun da leger ils parameters da sincronisaziun (per exempel per savair sche la sincronisaziun da contacts è activà u betg)."</string>
+    <!-- no translation found for permdesc_readSyncSettings (5464056785274229278) -->
+    <skip />
     <string name="permlab_writeSyncSettings" msgid="6297138566442486462">"scriver configuraziuns da sincronisaziun"</string>
-    <!-- outdated translation 2498201614431360044 -->     <string name="permdesc_writeSyncSettings" msgid="1466056564502117130">"Permetta ad ina applicaziun da modifitgar ils parameters da sincronisaziun. Uschia po ella per exempel activar e deactivar la sincronisaziun da contacts."</string>
+    <!-- no translation found for permdesc_writeSyncSettings (1466056564502117130) -->
+    <skip />
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"leger las statisticas da sincronisaziun"</string>
-    <!-- outdated translation 7511448343374465000 -->     <string name="permdesc_readSyncStats" msgid="3801971839939951678">"Permetta ad ina applicaziun da leger las statisticas da sincronisaziun (per exempel la cronologia da las sincronisaziuns exequidas)."</string>
+    <!-- no translation found for permdesc_readSyncStats (3801971839939951678) -->
+    <skip />
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"leger feeds abunads"</string>
-    <!-- outdated translation 3622200625634207660 -->     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permetta ad ina applicaziun dad obtegnair infurmaziuns davart ils feeds actualisads dacurt."</string>
+    <!-- no translation found for permdesc_subscribedFeedsRead (5557058907906144505) -->
+    <skip />
     <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"scriver feeds abunads"</string>
-    <!-- outdated translation 8121607099326533878 -->     <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Permetta ad ina applicaziun da modifitgar Voss feeds sincronisads dacurt. Applicaziuns donnegiusas pudessan uschia modifitgar Voss feeds sincronisads."</string>
-    <!-- outdated translation 432535716804748781 -->     <string name="permlab_readDictionary" msgid="8410247960433376352">"leger il dicziunari definì da l\'utilisader"</string>
-    <!-- outdated translation 1082972603576360690 -->     <string name="permdesc_readDictionary" msgid="8977815988329283705">"Permetta ad ina applicaziun da leger tut ils pleds e nums privats e las expressiuns privatas che in utilisader ha memorisà en ses dicziunari."</string>
-    <!-- outdated translation 6703109511836343341 -->     <string name="permlab_writeDictionary" msgid="2296383164914812772">"scriver en il dicziunari definì da l\'utilisader"</string>
-    <!-- outdated translation 2241256206524082880 -->     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Permetta ad ina applicaziun da scriver novs pleds en il dicziunari dal utilisader."</string>
-    <!-- outdated translation 8079403759001777291 -->     <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"modifitgar/stizzar cuntegns da la carta SD"</string>
+    <!-- no translation found for permdesc_subscribedFeedsWrite (6928930188826089413) -->
+    <skip />
+    <!-- no translation found for permlab_readDictionary (8410247960433376352) -->
+    <skip />
+    <!-- no translation found for permdesc_readDictionary (8977815988329283705) -->
+    <skip />
+    <!-- no translation found for permlab_writeDictionary (2296383164914812772) -->
+    <skip />
+    <!-- no translation found for permdesc_writeDictionary (8185385716255065291) -->
+    <skip />
+    <!-- no translation found for permlab_sdcardWrite (85430876310764752) -->
+    <skip />
     <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"modifitgar/stizzar cuntegns da la carta SD"</string>
-    <!-- outdated translation 6643963204976471878 -->     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Permetta ad ina applicaziun da scriver sin la carta SD."</string>
-    <!-- outdated translation 6643963204976471878 -->     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permetta ad ina applicaziun da scriver sin la carta SD."</string>
+    <!-- no translation found for permdesc_sdcardWrite (6175406299445710888) -->
+    <skip />
+    <!-- no translation found for permdesc_sdcardWrite (4337417790936632090) -->
+    <skip />
     <!-- no translation found for permlab_mediaStorageWrite (6859839199706879015) -->
     <skip />
     <!-- no translation found for permdesc_mediaStorageWrite (8189160597698529185) -->
     <skip />
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"access al sistem da datotecas da cache"</string>
-    <!-- outdated translation 1624734528435659906 -->     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permetta ad ina applicaziun da leger e da scriver en il sistem da datotecas dal cache."</string>
+    <!-- no translation found for permdesc_cache_filesystem (5578967642265550955) -->
+    <skip />
     <!-- no translation found for permlab_use_sip (5986952362795870502) -->
     <skip />
     <!-- no translation found for permdesc_use_sip (4717632000062674294) -->
@@ -548,33 +787,44 @@
     <skip />
     <!-- no translation found for permlab_modifyNetworkAccounting (5088217309088729650) -->
     <skip />
-    <!-- no translation found for permdesc_modifyNetworkAccounting (8553240749784321765) -->
+    <!-- no translation found for permdesc_modifyNetworkAccounting (5443412866746198123) -->
     <skip />
-    <!-- outdated translation 4307861496302850201 -->     <string name="policylab_limitPassword" msgid="4497420728857585791">"Limitar il pled-clav"</string>
-    <!-- outdated translation 1719877245692318299 -->     <string name="policydesc_limitPassword" msgid="9083400080861728056">"Restrenscher ils tips da pleds-clav che Vus pudais utilisar."</string>
-    <!-- outdated translation 7374780712664285321 -->     <string name="policylab_watchLogin" msgid="914130646942199503">"Survegliar las emprovas da s\'annunziar"</string>
-    <!-- outdated translation 1961251179624843483 -->     <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Survegliar las emprovas betg reussidas da s\'annunziar ad in apparat periferic / dad exequir ina acziun."</string>
-    <!-- outdated translation 1961251179624843483 -->     <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Survegliar las emprovas betg reussidas da s\'annunziar ad in apparat periferic / dad exequir ina acziun."</string>
-    <!-- outdated translation 9084772090797485420 -->     <string name="policylab_resetPassword" msgid="2620077191242688955">"Reinizialisar il pled-clav"</string>
-    <!-- outdated translation 3332167600331799991 -->     <string name="policydesc_resetPassword" msgid="5391240616981297361">"\"Definir ina nova valur per Voss pled-clav, uschia che l\'administratur As sto dar il pled-clav avant che Vus pudais s\'annunziar.\""</string>
-    <!-- outdated translation 5760466025247634488 -->     <string name="policylab_forceLock" msgid="2274085384704248431">"Sfurzar da bloccar"</string>
-    <!-- outdated translation 2819868664946089740 -->     <string name="policydesc_forceLock" msgid="5696964126226028442">"Controlla da la bloccaziun dad apparats periferics cun l\'obligaziun dad endatar danovamain il pled-clav."</string>
+    <!-- no translation found for policylab_limitPassword (4497420728857585791) -->
+    <skip />
+    <!-- no translation found for policydesc_limitPassword (3252114203919510394) -->
+    <skip />
+    <!-- no translation found for policylab_watchLogin (914130646942199503) -->
+    <skip />
+    <!-- no translation found for policydesc_watchLogin (3215729294215070072) -->
+    <skip />
+    <!-- no translation found for policydesc_watchLogin (5712323091846761073) -->
+    <skip />
+    <!-- no translation found for policylab_resetPassword (2620077191242688955) -->
+    <skip />
+    <!-- no translation found for policydesc_resetPassword (605963962301904458) -->
+    <skip />
+    <!-- no translation found for policylab_forceLock (2274085384704248431) -->
+    <skip />
+    <!-- no translation found for policydesc_forceLock (1141797588403827138) -->
+    <skip />
     <string name="policylab_wipeData" msgid="3910545446758639713">"Stizzar tut las datas"</string>
-    <!-- outdated translation 2314060933796396205 -->     <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Restaurar ils parameters originals dal telefonin. Qua tras vegnan tut Vossas datas stizzadas senza dumonda da conferma."</string>
-    <!-- outdated translation 2314060933796396205 -->     <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Restaurar ils parameters originals dal telefonin. Qua tras vegnan tut Vossas datas stizzadas senza dumonda da conferma."</string>
+    <!-- no translation found for policydesc_wipeData (4306184096067756876) -->
+    <skip />
+    <!-- no translation found for policydesc_wipeData (5096895604574188391) -->
+    <skip />
     <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir il proxy global da l\'apparat"</string>
     <string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Definir il proxy global da l\'apparat che duai vegnir utilisà sche la directiva è activada. Mo l\'emprim administratur dad apparats definescha il vair proxy global."</string>
     <!-- no translation found for policylab_expirePassword (885279151847254056) -->
     <skip />
-    <!-- no translation found for policydesc_expirePassword (4844430354224822074) -->
+    <!-- no translation found for policydesc_expirePassword (1729725226314691591) -->
     <skip />
     <!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
     <skip />
-    <!-- no translation found for policydesc_encryptedStorage (8877192718681120469) -->
+    <!-- no translation found for policydesc_encryptedStorage (2637732115325316992) -->
     <skip />
     <!-- no translation found for policylab_disableCamera (6395301023152297826) -->
     <skip />
-    <!-- no translation found for policydesc_disableCamera (5680054212889413366) -->
+    <!-- no translation found for policydesc_disableCamera (2306349042834754597) -->
     <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Privat"</item>
@@ -644,7 +894,8 @@
     <skip />
     <string name="eventTypeBirthday" msgid="2813379844211390740">"Anniversari"</string>
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"Anniversari"</string>
-    <!-- outdated translation 5834288791948564594 -->     <string name="eventTypeOther" msgid="7388178939010143077">"Termin"</string>
+    <!-- no translation found for eventTypeOther (7388178939010143077) -->
+    <skip />
     <string name="emailTypeCustom" msgid="8525960257804213846">"Persunalisà"</string>
     <string name="emailTypeHome" msgid="449227236140433919">"Privat"</string>
     <string name="emailTypeWork" msgid="3548058059601149973">"Lavur"</string>
@@ -709,7 +960,8 @@
     <skip />
     <!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
     <skip />
-    <!-- outdated translation 3731488827218876115 -->     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Endatar il code PIN"</string>
+    <!-- no translation found for keyguard_password_enter_pin_code (3037685796058495017) -->
+    <skip />
     <!-- no translation found for keyguard_password_enter_puk_code (4800725266925845333) -->
     <skip />
     <!-- no translation found for keyguard_password_enter_puk_prompt (1341112146710087048) -->
@@ -718,12 +970,16 @@
     <skip />
     <!-- no translation found for keyguard_password_entry_touch_hint (7858547464982981384) -->
     <skip />
-    <!-- outdated translation 9138158344813213754 -->     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Endatai il pled-clav per debloccar."</string>
-    <!-- outdated translation 638347075625491514 -->     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Endatar il PIN per debloccar"</string>
-    <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Code PIN nuncorrect!"</string>
+    <!-- no translation found for keyguard_password_enter_password_code (1054721668279049780) -->
+    <skip />
+    <!-- no translation found for keyguard_password_enter_pin_password_code (6391755146112503443) -->
+    <skip />
+    <!-- no translation found for keyguard_password_wrong_pin_code (2422225591006134936) -->
+    <skip />
     <string name="keyguard_label_text" msgid="861796461028298424">"Smatgai per debloccar sin la tasta Menu e lura sin 0."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numer d\'urgenza"</string>
-    <!-- outdated translation 8812714795156374435 -->     <string name="lockscreen_carrier_default" msgid="8963839242565653192">"(nagin servetsch)"</string>
+    <!-- no translation found for lockscreen_carrier_default (8963839242565653192) -->
+    <skip />
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Visur bloccà."</string>
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Smatgai la tasta Menu per debloccar il telefonin u telefonar sin in numer d\'urgenza."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Smatgar la tasta da menu per debloccar."</string>
@@ -731,17 +987,23 @@
     <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Numer d\'urgenza"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Enavos al clom"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correct!"</string>
-    <!-- outdated translation 4817583279053112312 -->     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Quai ans displascha. Empruvai anc ina giada."</string>
-    <!-- outdated translation 6237443657358168819 -->     <string name="lockscreen_password_wrong" msgid="5737815393253165301">"\"Perstgisai, empruvai anc ina giada.\""</string>
+    <!-- no translation found for lockscreen_pattern_wrong (4317955014948108794) -->
+    <skip />
+    <!-- no translation found for lockscreen_password_wrong (5737815393253165301) -->
+    <skip />
+    <!-- no translation found for faceunlock_multiple_failures (754137583022792429) -->
+    <skip />
     <!-- no translation found for lockscreen_plugged_in (8057762828355572315) -->
     <skip />
     <string name="lockscreen_charged" msgid="4938930459620989972">"Chargià"</string>
     <string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Connectai Voss chargiader."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Nagina carta SIM."</string>
-    <!-- outdated translation 2186920585695169078 -->     <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"En il telefon na sa chatta nagina carta SIM."</string>
+    <!-- no translation found for lockscreen_missing_sim_message (151659196095791474) -->
+    <skip />
     <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"En il telefon na sa chatta nagina carta SIM."</string>
-    <!-- outdated translation 8874620818937719067 -->     <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inseri per plaschair ina carta SIM."</string>
+    <!-- no translation found for lockscreen_missing_sim_instructions (5372787138023272615) -->
+    <skip />
     <!-- no translation found for lockscreen_missing_sim_instructions_long (3526573099019319472) -->
     <skip />
     <!-- no translation found for lockscreen_permanent_disabled_sim_instructions (910904643433151371) -->
@@ -760,7 +1022,8 @@
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rait bloccada"</string>
     <!-- no translation found for lockscreen_sim_puk_locked_message (7441797339976230) -->
     <skip />
-    <!-- outdated translation 635967534992394321 -->     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Ulteriuras infurmaziuns chattais Vus en il manual u che Vus pudais contactar il servetsch da clientella."</string>
+    <!-- no translation found for lockscreen_sim_puk_locked_instructions (8127916255245181063) -->
+    <skip />
     <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La carta SIM è bloccada."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Debloccar la carta SIM..."</string>
     <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6481623830344107222) -->
@@ -784,15 +1047,18 @@
     <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Empruvar anc ina giada en <xliff:g id="NUMBER">%d</xliff:g> secundas."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Emblidà il schema?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Debloccaziun dal conto"</string>
-    <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Memia bleras tentativas!"</string>
-    <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"S\'annunziai cun Voss conto Google per debloccar il telefonin."</string>
+    <!-- no translation found for lockscreen_glogin_too_many_attempts (2751368605287288808) -->
+    <skip />
+    <!-- no translation found for lockscreen_glogin_instructions (3931816256100707784) -->
+    <skip />
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Num d\'utilisader (e-mail)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Pled-clav"</string>
     <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"S\'annunziar"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Num d\'utilisader u pled-clav nunvalid."</string>
-    <!-- no translation found for lockscreen_glogin_account_recovery_hint (8253152905532900548) -->
+    <!-- no translation found for lockscreen_glogin_account_recovery_hint (1696924763690379073) -->
     <skip />
-    <string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Verifitgar..."</string>
+    <!-- no translation found for lockscreen_glogin_checking_password (7114627351286933867) -->
+    <skip />
     <string name="lockscreen_unlock_label" msgid="737440483220667054">"Debloccar"</string>
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Tun activà"</string>
     <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Tun deactivà"</string>
@@ -813,15 +1079,17 @@
     <string name="factorytest_not_system" msgid="4435201656767276723">"L\'acziun FACTORY_TEST vegn mo sustegnida per pachets installads en /system/app."</string>
     <string name="factorytest_no_action" msgid="872991874799998561">"Betg chattà in pachet che porscha l\'acziun FACTORY_TEST."</string>
     <string name="factorytest_reboot" msgid="6320168203050791643">"Reaviar il sistem"</string>
-    <string name="js_dialog_title" msgid="8143918455087008109">"La pagina \'<xliff:g id="TITLE">%s</xliff:g>\' annunzia:"</string>
+    <!-- no translation found for js_dialog_title (1987483977834603872) -->
+    <skip />
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
     <!-- no translation found for js_dialog_before_unload (730366588032430474) -->
     <skip />
     <string name="save_password_label" msgid="6860261758665825069">"Confermar"</string>
-    <!-- outdated translation 1068216937244567247 -->     <string name="double_tap_toast" msgid="2729045387923870404">"Tip: Smatgar duas giadas per zoomar pli datiers u zoomar pli lontan."</string>
-    <!-- no translation found for autofill_this_form (1272247532604569872) -->
+    <!-- no translation found for double_tap_toast (4595046515400268881) -->
     <skip />
-    <!-- no translation found for setup_autofill (8154593408885654044) -->
+    <!-- no translation found for autofill_this_form (4616758841157816676) -->
+    <skip />
+    <!-- no translation found for setup_autofill (7103495070180590814) -->
     <skip />
     <!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
     <skip />
@@ -856,10 +1124,13 @@
     <!-- no translation found for autofill_emirate (2893880978835698818) -->
     <skip />
     <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leger la cronologia ed ils segnapaginas dal navigatur"</string>
-    <!-- outdated translation 4981489815467617191 -->     <string name="permdesc_readHistoryBookmarks" msgid="4577476392604595921">"\"Permetta a l\'applicaziun da leger tut las URLs visitadas, sco era ils segnapaginas dal navigatur.\""</string>
+    <!-- no translation found for permdesc_readHistoryBookmarks (4577476392604595921) -->
+    <skip />
     <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"scriver en la cronologia ed en ils segnapaginas dal navigatur"</string>
-    <!-- outdated translation 945571990357114950 -->     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="1757103804824209530">"\"Permetta ad ina applicaziun da modifitgar la cronologia u ils segnapaginas dal navigatur, memorisads sin Voss telefonin. Applicaziuns donnegiusas pon uschia stizzar u modifitgar las datas da Voss navigatur.\""</string>
-    <!-- outdated translation 945571990357114950 -->     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"\"Permetta ad ina applicaziun da modifitgar la cronologia u ils segnapaginas dal navigatur, memorisads sin Voss telefonin. Applicaziuns donnegiusas pon uschia stizzar u modifitgar las datas da Voss navigatur.\""</string>
+    <!-- no translation found for permdesc_writeHistoryBookmarks (1757103804824209530) -->
+    <skip />
+    <!-- no translation found for permdesc_writeHistoryBookmarks (6693764355720719197) -->
+    <skip />
     <!-- no translation found for permlab_setAlarm (5924401328803615165) -->
     <skip />
     <!-- no translation found for permdesc_setAlarm (316392039157473848) -->
@@ -868,8 +1139,10 @@
     <skip />
     <!-- no translation found for permdesc_addVoicemail (6604508651428252437) -->
     <skip />
-    <!-- outdated translation 4715212655598275532 -->     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Modifitgar las autorisaziuns da geolocalisaziun dal navigatur"</string>
-    <!-- outdated translation 4011908282980861679 -->     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permetta ad ina applicaziun da modifitgar las permissiuns da geolocalisaziun dal navigatur. Applicaziuns donnegiusas pon utilisar questa funcziun per trametter datas da posiziun a websites arbitraras."</string>
+    <!-- no translation found for permlab_writeGeolocationPermissions (5962224158955273932) -->
+    <skip />
+    <!-- no translation found for permdesc_writeGeolocationPermissions (1083743234522638747) -->
+    <skip />
     <!-- no translation found for permlab_packageVerificationAgent (5568139100645829117) -->
     <skip />
     <!-- no translation found for permdesc_packageVerificationAgent (8437590190990843381) -->
@@ -878,11 +1151,16 @@
     <skip />
     <!-- no translation found for permdesc_bindPackageVerifier (3180741773233862126) -->
     <skip />
+    <!-- no translation found for permlab_serialPort (546083327654631076) -->
+    <skip />
+    <!-- no translation found for permdesc_serialPort (2991639985224598193) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Vulais Vus ch\'il navigatur memorisescha quest pled-clav?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Betg ussa"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Memorisar"</string>
     <string name="save_password_never" msgid="8274330296785855105">"Mai"</string>
-    <!-- outdated translation 5661861460947222274 -->     <string name="open_permission_deny" msgid="7374036708316629800">"Vus n\'avais betg las permissiuns necessarias per avrir questa pagina."</string>
+    <!-- no translation found for open_permission_deny (7374036708316629800) -->
+    <skip />
     <string name="text_copied" msgid="4985729524670131385">"Il text è vegnì copià en l\'archiv provisoric."</string>
     <string name="more_item_label" msgid="4650918923083320495">"Dapli"</string>
     <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
@@ -986,9 +1264,12 @@
     <string name="weeks" msgid="6509623834583944518">"emnas"</string>
     <string name="year" msgid="4001118221013892076">"onn"</string>
     <string name="years" msgid="6881577717993213522">"onns"</string>
-    <!-- outdated translation 3359437293118172396 -->     <string name="VideoView_error_title" msgid="5927895235831021723">"Betg reussì da reproducir il video."</string>
-    <!-- outdated translation 897920883624437033 -->     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"\"Perstgisai, deplorablamain n\'è quest video betg valid per il streaming sin quest apparat.\""</string>
-    <!-- outdated translation 710301040038083944 -->     <string name="VideoView_error_text_unknown" msgid="4309847331399592194">"\"Perstgisai, impussibel da leger quest video.\""</string>
+    <!-- no translation found for VideoView_error_title (3534509135438353077) -->
+    <skip />
+    <!-- no translation found for VideoView_error_text_invalid_progressive_playback (3186670335938670444) -->
+    <skip />
+    <!-- no translation found for VideoView_error_text_unknown (3450439155187810085) -->
+    <skip />
     <string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
     <string name="relative_time" msgid="1818557177829411417">"\"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>\""</string>
     <string name="noon" msgid="7245353528818587908">"mezdi"</string>
@@ -1006,10 +1287,9 @@
     <!-- no translation found for delete (6098684844021697789) -->
     <skip />
     <string name="copyUrl" msgid="2538211579596067402">"Copiar l\'URL"</string>
-    <!-- outdated translation 6738556348861347240 -->     <string name="selectTextMode" msgid="1018691815143165326">"Selecziunar text…"</string>
-    <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selecziun da text"</string>
-    <!-- unknown placeholder WORD in addToDictionary -->
+    <!-- no translation found for selectTextMode (1018691815143165326) -->
     <skip />
+    <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selecziun da text"</string>
     <!-- no translation found for addToDictionary (9090375111134433012) -->
     <skip />
     <!-- no translation found for deleteText (7070985395199629156) -->
@@ -1017,23 +1297,28 @@
     <string name="inputMethod" msgid="1653630062304567879">"Metoda d\'endataziun"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acziuns da text"</string>
     <string name="low_internal_storage_view_title" msgid="1399732408701697546">"Pauca capacitad da memorisar"</string>
-    <!-- outdated translation 635106544616378836 -->     <string name="low_internal_storage_view_text" product="tablet" msgid="4231085657068852042">"Mo pli pauca capacitad da memorisar."</string>
+    <!-- no translation found for low_internal_storage_view_text (4231085657068852042) -->
+    <skip />
     <string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Mo pli pauca capacitad da memorisar."</string>
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Interrumper"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
     <string name="no" msgid="5141531044935541497">"Interrumper"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Attenziun"</string>
-    <!-- outdated translation 1760724998928255250 -->     <string name="loading" msgid="7933681260296021180">"Chargiar…"</string>
+    <!-- no translation found for loading (7933681260296021180) -->
+    <skip />
     <string name="capital_on" msgid="1544682755514494298">"ACTIVÀ"</string>
     <string name="capital_off" msgid="6815870386972805832">"DEACTIVÀ"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Cumplettar l\'acziun cun"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Utilisar questa applicaziun sco standard per questa acziun."</string>
-    <!-- outdated translation 4815455344600932173 -->     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Stizzar ils parameters da standard en Parameters da la pagina da partenza &gt; Applicaziuns &gt; Administrar las applicaziuns."</string>
-    <string name="chooseActivity" msgid="1009246475582238425">"Tscherner ina acziun"</string>
+    <!-- no translation found for clearDefaultHintMsg (3252584689512077257) -->
+    <skip />
+    <!-- no translation found for chooseActivity (7486876147751803333) -->
+    <skip />
     <!-- no translation found for chooseUsbActivity (6894748416073583509) -->
     <skip />
-    <!-- outdated translation 1691104391758345586 -->     <string name="noApplications" msgid="2991814273936504689">"Nagina applicaziun po exequir questa acziun."</string>
+    <!-- no translation found for noApplications (2991814273936504689) -->
+    <skip />
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <!-- no translation found for aerr_application (932628488013092776) -->
     <skip />
@@ -1048,9 +1333,12 @@
     <skip />
     <!-- no translation found for anr_process (6513209874880517125) -->
     <skip />
-    <!-- outdated translation 3653416315450806396 -->     <string name="force_close" msgid="8346072094521265605">"Sfurzar da serrar"</string>
+    <!-- no translation found for force_close (8346072094521265605) -->
+    <skip />
     <string name="report" msgid="4060218260984795706">"Rapport"</string>
     <string name="wait" msgid="7147118217226317732">"Spetgar"</string>
+    <!-- no translation found for webpage_unresponsive (3272758351138122503) -->
+    <skip />
     <!-- no translation found for launch_warning_title (1547997780506713581) -->
     <skip />
     <!-- no translation found for launch_warning_replace (6202498949970281412) -->
@@ -1075,18 +1363,25 @@
     <!-- no translation found for android_upgrading_complete (1405954754112999229) -->
     <skip />
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> vegn exequida"</string>
-    <!-- outdated translation 2423977499339403402 -->     <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Tscherner per midar a l\'applicaziun"</string>
-    <!-- outdated translation 1135403633766694316 -->     <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Midar dad ina applicaziun a l\'autra?"</string>
-    <!-- outdated translation 4592075610079319667 -->     <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ina autra applicaziun vegn gia exequida e sto vegnir serrada avant ch\'ina nova po vegnir aviada."</string>
+    <!-- no translation found for heavy_weight_notification_detail (1721681741617898865) -->
+    <skip />
+    <!-- no translation found for heavy_weight_switcher_title (7153167085403298169) -->
+    <skip />
+    <!-- no translation found for heavy_weight_switcher_text (7022631924534406403) -->
+    <skip />
     <string name="old_app_action" msgid="493129172238566282">"Turnar a <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
-    <!-- outdated translation 942967900237208466 -->     <string name="old_app_description" msgid="2082094275580358049">"Betg aviai la nova applicaziun."</string>
+    <!-- no translation found for old_app_description (2082094275580358049) -->
+    <skip />
     <string name="new_app_action" msgid="5472756926945440706">"Aviar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
-    <!-- outdated translation 6830398339826789493 -->     <string name="new_app_description" msgid="1932143598371537340">"Fermai l\'applicaziun veglia senza memorisar."</string>
-    <string name="sendText" msgid="5132506121645618310">"Tscherner ina acziun per il text"</string>
+    <!-- no translation found for new_app_description (1932143598371537340) -->
+    <skip />
+    <!-- no translation found for sendText (5209874571959469142) -->
+    <skip />
     <string name="volume_ringtone" msgid="6885421406845734650">"Volumen dal tun da scalin"</string>
     <string name="volume_music" msgid="5421651157138628171">"Volumen da medias"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproducir tras bluetooth"</string>
-    <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Tschernì il modus silenzius per il tun da scalin"</string>
+    <!-- no translation found for volume_music_hint_silent_ringtone_selected (8310739960973156272) -->
+    <skip />
     <string name="volume_call" msgid="3941680041282788711">"Volumen dals cloms entrants"</string>
     <string name="volume_bluetooth_call" msgid="2002891926351151534">"Volumen da cloms entrants da bluetooth"</string>
     <string name="volume_alarm" msgid="1985191616042689100">"Volumen dal svegliarin"</string>
@@ -1115,34 +1410,46 @@
     <item quantity="one" msgid="1634101450343277345">"Rait WLAN averta disponibla"</item>
     <item quantity="other" msgid="7915895323644292768">"Raits WLAN avertas disponiblas"</item>
   </plurals>
-    <!-- no translation found for wifi_available_sign_in (9157196203958866662) -->
+    <!-- no translation found for wifi_available_sign_in (4029489716605255386) -->
     <skip />
     <!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) -->
     <skip />
     <!-- no translation found for wifi_watchdog_network_disabled (7904214231651546347) -->
     <skip />
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+    <!-- no translation found for wifi_watchdog_network_disabled_detailed (5548780776418332675) -->
     <skip />
     <!-- no translation found for wifi_p2p_dialog_title (97611782659324517) -->
     <skip />
-    <!-- no translation found for wifi_p2p_turnon_message (2804722042556269129) -->
+    <!-- no translation found for wifi_p2p_turnon_message (2909250942299627244) -->
     <skip />
-    <!-- no translation found for wifi_p2p_failed_message (1820097493844848281) -->
+    <!-- no translation found for wifi_p2p_failed_message (3763669677935623084) -->
     <skip />
-    <!-- no translation found for wifi_p2p_pbc_go_negotiation_request_message (3170321684621420428) -->
+    <!-- no translation found for accept (1645267259272829559) -->
     <skip />
-    <!-- no translation found for wifi_p2p_pin_go_negotiation_request_message (5177412094633377308) -->
+    <!-- no translation found for decline (2112225451706137894) -->
     <skip />
-    <!-- no translation found for wifi_p2p_pin_display_message (2834049169114922902) -->
+    <!-- no translation found for wifi_p2p_invitation_sent_title (1318975185112070734) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_invitation_to_connect_title (4958803948658533637) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_from_message (570389174731951769) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_to_message (248968974522044099) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_enter_pin_message (5920929550367828970) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_show_pin_message (8530563323880921094) -->
     <skip />
     <!-- no translation found for wifi_p2p_enabled_notification_title (2068321881673734886) -->
     <skip />
     <!-- no translation found for wifi_p2p_enabled_notification_message (1638949953993894335) -->
     <skip />
     <string name="select_character" msgid="3365550120617701745">"Inserir in caracter"</string>
-    <!-- outdated translation 7630529934366549163 -->     <string name="sms_control_default_app_name" msgid="3058577482636640465">"Applicaziun nunenconuschenta"</string>
+    <!-- no translation found for sms_control_default_app_name (3058577482636640465) -->
+    <skip />
     <string name="sms_control_title" msgid="7296612781128917719">"Trametter messadis SMS"</string>
-    <!-- outdated translation 1289331457999236205 -->     <string name="sms_control_message" msgid="4073755190243093924">"Vulais Vus trametter in grond dumber da messadis SMS? Tschernì OK per cuntinuar u Interrumper per annullar la spediziun."</string>
+    <!-- no translation found for sms_control_message (4073755190243093924) -->
+    <skip />
     <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
     <string name="sms_control_no" msgid="1715320703137199869">"Interrumper"</string>
     <!-- no translation found for sim_removed_title (6227712319223226185) -->
@@ -1153,7 +1460,7 @@
     <skip />
     <!-- no translation found for sim_added_title (3719670512889674693) -->
     <skip />
-    <!-- no translation found for sim_added_message (1209265974048554242) -->
+    <!-- no translation found for sim_added_message (6599945301141050216) -->
     <skip />
     <!-- no translation found for sim_restart_button (4722407842815232347) -->
     <skip />
@@ -1166,25 +1473,37 @@
     <string name="no_permissions" msgid="7283357728219338112">"Naginas permissiuns obligatoricas"</string>
     <string name="perms_hide" msgid="7283915391320676226"><b>"Zuppentar"</b></string>
     <string name="perms_show_all" msgid="2671791163933091180"><b>"Mussar tut"</b></string>
-    <string name="usb_storage_activity_title" msgid="2399289999608900443">"Memoria da massa USB"</string>
+    <!-- no translation found for usb_storage_activity_title (4465055157209648641) -->
+    <skip />
     <string name="usb_storage_title" msgid="5901459041398751495">"Connectà cun agid d\'in cabel USB"</string>
-    <!-- outdated translation 4796759646167247178 -->     <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"\"Vus avais connectà Voss telefonin cun Voss computer cun agid dad in cabel USB. Tscherni il buttun sutvart per copiar datotecas da Voss computer sin la carta SD da Voss Android, u viceversa.\""</string>
-    <!-- outdated translation 4796759646167247178 -->     <string name="usb_storage_message" product="default" msgid="4510858346516069238">"\"Vus avais connectà Voss telefonin cun Voss computer cun agid dad in cabel USB. Tscherni il buttun sutvart per copiar datotecas da Voss computer sin la carta SD da Voss Android, u viceversa.\""</string>
+    <!-- no translation found for usb_storage_message (3308538094316477839) -->
+    <skip />
+    <!-- no translation found for usb_storage_message (805351000446037811) -->
+    <skip />
     <string name="usb_storage_button_mount" msgid="1052259930369508235">"Activar la memoria USB"</string>
-    <!-- outdated translation 2534784751603345363 -->     <string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Cun l\'utilisaziun da Vossa carta SD sco memoria USB è cumparì in problem."</string>
-    <!-- outdated translation 2534784751603345363 -->     <string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Cun l\'utilisaziun da Vossa carta SD sco memoria USB è cumparì in problem."</string>
+    <!-- no translation found for usb_storage_error_message (3017045217365540658) -->
+    <skip />
+    <!-- no translation found for usb_storage_error_message (2876018512716970313) -->
+    <skip />
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"Connectà cun in cabel USB"</string>
-    <string name="usb_storage_notification_message" msgid="7380082404288219341">"Tscherni las datotecas che duain vegnir copiadas da/sin Voss computer."</string>
+    <!-- no translation found for usb_storage_notification_message (939822783828183763) -->
+    <skip />
     <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Deactivar la memoria USB"</string>
-    <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Tscherner per deactivar la memoria USB."</string>
+    <!-- no translation found for usb_storage_stop_notification_message (1656852098555623822) -->
+    <skip />
     <string name="usb_storage_stop_title" msgid="660129851708775853">"La memoria USB vegn gest utilisada"</string>
-    <!-- outdated translation 3613713396426604104 -->     <string name="usb_storage_stop_message" product="nosdcard" msgid="1368842269463745067">"Verifitgai avant che deactivar la memoria USB che Vus avais demontà la carta SD Android da Voss computer."</string>
-    <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Verifitgai avant che deactivar la memoria USB che Vus avais demontà la carta SD Android da Voss computer."</string>
+    <!-- no translation found for usb_storage_stop_message (4264025280777219521) -->
+    <skip />
+    <!-- no translation found for usb_storage_stop_message (8043969782460613114) -->
+    <skip />
     <string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Deactivar l\'apparat periferic da memoria USB"</string>
-    <string name="usb_storage_stop_error_message" msgid="143881914840412108">"Cun deactivar la memoria USB è in problem cumparì. Verifitgai che Vus avais demontà il host USB ed empruvai anc ina giada."</string>
+    <!-- no translation found for usb_storage_stop_error_message (1970374898263063836) -->
+    <skip />
     <string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Activar la memoria USB"</string>
-    <!-- outdated translation 3202838234780505886 -->     <string name="dlg_confirm_kill_storage_users_text" msgid="6206212680430268343">"Sche Vus activais l\'apparat periferic da memoria USB sa ferman tschertas applicaziuns che Vus utilisais. Ellas n\'èn probablamain betg disponiblas enfin che l\'apparat periferic vegn puspè deactivà."</string>
-    <!-- outdated translation 8048999973837339174 -->     <string name="dlg_error_title" msgid="7323658469626514207">"Operaziun USB betg reussida"</string>
+    <!-- no translation found for dlg_confirm_kill_storage_users_text (5100428757107469454) -->
+    <skip />
+    <!-- no translation found for dlg_error_title (7323658469626514207) -->
+    <skip />
     <string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
     <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
     <skip />
@@ -1194,51 +1513,76 @@
     <skip />
     <!-- no translation found for usb_accessory_notification_title (7848236974087653666) -->
     <skip />
-    <!-- no translation found for usb_notification_message (4447869605109736382) -->
+    <!-- no translation found for usb_notification_message (2290859399983720271) -->
     <skip />
-    <!-- outdated translation 8663247929551095854 -->     <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Formatar la carta SD"</string>
-    <!-- outdated translation 8663247929551095854 -->     <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Formatar la carta SD"</string>
-    <!-- outdated translation 3621369962433523619 -->     <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Vulais Vus propi formatar la carta SD? En quest cas van tut las datas sin Vossa carta a perder."</string>
-    <!-- outdated translation 3621369962433523619 -->     <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Vulais Vus propi formatar la carta SD? En quest cas van tut las datas sin Vossa carta a perder."</string>
+    <!-- no translation found for extmedia_format_title (9020092196061007262) -->
+    <skip />
+    <!-- no translation found for extmedia_format_title (3648415921526526069) -->
+    <skip />
+    <!-- no translation found for extmedia_format_message (3934016853425761078) -->
+    <skip />
+    <!-- no translation found for extmedia_format_message (14131895027543830) -->
+    <skip />
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB connectà"</string>
-    <!-- outdated translation 8470296818270110396 -->     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tscherner per deactivar il debugging USB."</string>
-    <!-- outdated translation 6865512749462072765 -->     <string name="select_input_method" msgid="4653387336791222978">"Tscherner ina metoda d\'endataziun"</string>
+    <!-- no translation found for adb_active_notification_message (1016654627626476142) -->
+    <skip />
+    <!-- no translation found for select_input_method (4653387336791222978) -->
+    <skip />
     <!-- no translation found for configure_input_methods (9091652157722495116) -->
     <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
-    <!-- outdated translation 5457603418970994050 -->     <string name="ext_media_checking_notification_title" product="nosdcard" msgid="3449816005351468560">"Preparaziun da la carta SD"</string>
+    <!-- no translation found for ext_media_checking_notification_title (3449816005351468560) -->
+    <skip />
     <string name="ext_media_checking_notification_title" product="default" msgid="5457603418970994050">"Preparaziun da la carta SD"</string>
     <string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Tschertgar errurs"</string>
-    <!-- outdated translation 780477838241212997 -->     <string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"Carta SD vida"</string>
+    <!-- no translation found for ext_media_nofs_notification_title (7788040745686229307) -->
+    <skip />
     <string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"Carta SD vida"</string>
-    <!-- outdated translation 1312266820092958014 -->     <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"La carta SD è vida u ch\'ella utilisescha in sistem da datotecas che na vegn betg sustegnì."</string>
-    <string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"La carta SD è vida ubain che ses sistem da datotecas na vegn betg sustegnì."</string>
-    <!-- outdated translation 6410723906019100189 -->     <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Carta SD donnegiada"</string>
+    <!-- no translation found for ext_media_nofs_notification_message (7840121067427269500) -->
+    <skip />
+    <!-- no translation found for ext_media_nofs_notification_message (8641065641786923604) -->
+    <skip />
+    <!-- no translation found for ext_media_unmountable_notification_title (2090046769532713563) -->
+    <skip />
     <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Carta SD donnegiada"</string>
-    <!-- outdated translation 2679412884290061775 -->     <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"La carta SD è donnegiada. Vus stuais eventualmain reformatar Vossa carta."</string>
-    <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"La carta SD è donnegiada. Vus stuais eventualmain reformatar la carta."</string>
-    <!-- outdated translation 6872152882604407837 -->     <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"Allontanà la carta SD nunspetgadamain"</string>
+    <!-- no translation found for ext_media_unmountable_notification_message (1795917578395333280) -->
+    <skip />
+    <!-- no translation found for ext_media_unmountable_notification_message (1753898567525568253) -->
+    <skip />
+    <!-- no translation found for ext_media_badremoval_notification_title (1661683031330951073) -->
+    <skip />
     <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Allontanà la carta SD nunspetgadamain"</string>
-    <!-- outdated translation 7260183293747448241 -->     <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Demontar la carta SD avant che retrair ella per evitar ina sperdita da datas."</string>
+    <!-- no translation found for ext_media_badremoval_notification_message (4329848819865594241) -->
+    <skip />
     <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Demontar la carta SD avant che retrair ella per evitar ina sperdita da datas."</string>
-    <!-- outdated translation 6729801130790616200 -->     <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"La carta SD po vegnir allontanada a moda segira"</string>
+    <!-- no translation found for ext_media_safe_unmount_notification_title (3967973893270360230) -->
+    <skip />
     <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"La carta SD po vegnir allontanada a moda segira"</string>
-    <!-- outdated translation 7613960686747592770 -->     <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"La carta SD po ussa vegnir allontanada."</string>
+    <!-- no translation found for ext_media_safe_unmount_notification_message (6142195361606493530) -->
+    <skip />
     <string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"La carta SD po vegnir retratga a moda segira."</string>
-    <!-- outdated translation 8902518030404381318 -->     <string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"Allontanà la carta SD"</string>
+    <!-- no translation found for ext_media_nomedia_notification_title (4486377230140227651) -->
+    <skip />
     <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Allontanà la carta SD"</string>
-    <!-- outdated translation 4205117227342822275 -->     <string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"La carta SD è vegnida allontanada. Inseri ina carta SD nova per engrondir la capacitad da memorisar da Voss apparat."</string>
+    <!-- no translation found for ext_media_nomedia_notification_message (6921126162580574143) -->
+    <skip />
     <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"Allontanà la carta SD. Inseri ina nova."</string>
-    <string name="activity_list_empty" msgid="4168820609403385789">"Betg chattà activitads correspundentas"</string>
+    <!-- no translation found for activity_list_empty (1675388330786841066) -->
+    <skip />
     <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualisar las datas statisticas da la cumponenta"</string>
-    <!-- outdated translation 891553695716752835 -->     <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Permetta da modifitgar las datas statisticas rimnadas da la cumponenta. Betg previs per applicaziuns normalas."</string>
-    <!-- outdated translation 1660908117394854464 -->     <string name="permlab_copyProtectedData" msgid="4341036311211406692">"Permetta da clamar il servetsch da container predefinì per copiar il cuntegn. Betg previs per applicaziuns normalas."</string>
-    <!-- outdated translation 537780957633976401 -->     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permetta da clamar il servetsch da container predefinì per copiar il cuntegn. Betg previs per applicaziuns normalas."</string>
-    <!-- outdated translation 1311810005957319690 -->     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tutgar duas giadas per reglar il zoom"</string>
-    <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Errur cun engrondir il widget"</string>
+    <!-- no translation found for permdesc_pkgUsageStats (1106612424254277630) -->
+    <skip />
+    <!-- no translation found for permlab_copyProtectedData (4341036311211406692) -->
+    <skip />
+    <!-- no translation found for permdesc_copyProtectedData (4390697124288317831) -->
+    <skip />
+    <!-- no translation found for tutorial_double_tap_to_zoom_message_short (4070433208160063538) -->
+    <skip />
+    <!-- no translation found for gadget_host_error_inflating (4882004314906466162) -->
+    <skip />
     <string name="ime_action_go" msgid="8320845651737369027">"Dai"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Tschertgar"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"Trametter"</string>
@@ -1249,41 +1593,49 @@
     <string name="ime_action_default" msgid="2840921885558045721">"Exequir"</string>
     <string name="dial_number_using" msgid="5789176425167573586">"Cumponer il numer"\n"cun utilisar <xliff:g id="NUMBER">%s</xliff:g>"</string>
     <string name="create_contact_using" msgid="4947405226788104538">"Agiuntar in contact"\n"cun il numer <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <!-- outdated translation 6824538733852821001 -->     <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Las suandantas applicaziuns dumondan l\'autorisaziun dad acceder a partir dad ussa a Voss conto."</string>
+    <!-- no translation found for grant_credentials_permission_message_header (2106103817937859662) -->
+    <skip />
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vulais Vus autorisar questa dumonda?"</string>
-    <string name="grant_permissions_header_text" msgid="2722567482180797717">"Dumonda d\'access"</string>
+    <!-- no translation found for grant_permissions_header_text (6874497408201826708) -->
+    <skip />
     <string name="allow" msgid="7225948811296386551">"Permetter"</string>
     <string name="deny" msgid="2081879885755434506">"Refusar"</string>
-    <string name="permission_request_notification_title" msgid="5390555465778213840">"Autorisaziun dumandada"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Autorisaziun dumandada"\n"per il conto <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <!-- no translation found for permission_request_notification_title (6486759795926237907) -->
+    <skip />
+    <!-- no translation found for permission_request_notification_with_subtitle (8530393139639560189) -->
+    <skip />
     <string name="input_method_binding_label" msgid="1283557179944992649">"Metoda d\'endataziun"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sincronisar"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Agids d\'access"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Fund davos"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Midar il fund davos"</string>
-    <!-- no translation found for vpn_title (8219003246858087489) -->
+    <!-- no translation found for vpn_title (19615213552042827) -->
     <skip />
     <!-- no translation found for vpn_title_long (6400714798049252294) -->
     <skip />
-    <!-- no translation found for vpn_text (1610714069627824309) -->
+    <!-- no translation found for vpn_text (3011306607126450322) -->
     <skip />
-    <!-- no translation found for vpn_text_long (4907843483284977618) -->
+    <!-- no translation found for vpn_text_long (6407351006249174473) -->
     <skip />
     <string name="upload_file" msgid="2897957172366730416">"Tscherner ina datoteca"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nagina datoteca tschernida"</string>
     <string name="reset" msgid="2448168080964209908">"Reinizialisar"</string>
     <string name="submit" msgid="1602335572089911941">"Trametter"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Modus dad auto activà"</string>
-    <string name="car_mode_disable_notification_message" msgid="668663626721675614">"Tscherner per serrar il modus dad auto."</string>
+    <!-- no translation found for car_mode_disable_notification_message (8035230537563503262) -->
+    <skip />
     <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering u hotspot activ"</string>
-    <string name="tethered_notification_message" msgid="3067108323903048927">"Tutgar per configurar"</string>
+    <!-- no translation found for tethered_notification_message (6857031760103062982) -->
+    <skip />
     <string name="back_button_label" msgid="2300470004503343439">"Enavos"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Vinavant"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Sursiglir"</string>
     <string name="throttle_warning_notification_title" msgid="4890894267454867276">"Grond diever da datas mobilas"</string>
-    <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Tutgar per vegnir a savair dapli davart l\'utilisaziun da datas mobilas"</string>
+    <!-- no translation found for throttle_warning_notification_message (3340822228599337743) -->
+    <skip />
     <string name="throttled_notification_title" msgid="6269541897729781332">"Surpassà la limita da datas mobilas"</string>
-    <string name="throttled_notification_message" msgid="4712369856601275146">"Tutgar per vegnir a savair dapli davart l\'utilisaziun da datas mobilas"</string>
+    <!-- no translation found for throttled_notification_message (5443457321354907181) -->
+    <skip />
     <!-- no translation found for no_matches (8129421908915840737) -->
     <skip />
     <!-- no translation found for find_on_page (1946799233822820384) -->
@@ -1292,13 +1644,13 @@
     <!-- no translation found for matches_found:other (4641872797067609177) -->
     <!-- no translation found for action_mode_done (7217581640461922289) -->
     <skip />
-    <!-- no translation found for progress_unmounting (535863554318797377) -->
+    <!-- no translation found for progress_unmounting (3923810448507612746) -->
     <skip />
-    <!-- no translation found for progress_unmounting (5556813978958789471) -->
+    <!-- no translation found for progress_unmounting (1327894998409537190) -->
     <skip />
-    <!-- no translation found for progress_erasing (4183664626203056915) -->
+    <!-- no translation found for progress_erasing (4521573321524340058) -->
     <skip />
-    <!-- no translation found for progress_erasing (2115214724367534095) -->
+    <!-- no translation found for progress_erasing (6596988875507043042) -->
     <skip />
     <!-- no translation found for format_error (6299769563624776948) -->
     <skip />
@@ -1336,19 +1688,19 @@
     <skip />
     <!-- no translation found for sync_too_many_deletes (5296321850662746890) -->
     <skip />
-    <!-- no translation found for sync_too_many_deletes_desc (7030265992955132593) -->
+    <!-- no translation found for sync_too_many_deletes_desc (496551671008694245) -->
     <skip />
-    <!-- no translation found for sync_really_delete (8933566316059338692) -->
+    <!-- no translation found for sync_really_delete (2572600103122596243) -->
     <skip />
-    <!-- no translation found for sync_undo_deletes (8610996708225006328) -->
+    <!-- no translation found for sync_undo_deletes (2941317360600338602) -->
     <skip />
-    <!-- no translation found for sync_do_nothing (8717589462945226869) -->
+    <!-- no translation found for sync_do_nothing (3743764740430821845) -->
     <skip />
     <!-- no translation found for choose_account_label (5655203089746423927) -->
     <skip />
     <!-- no translation found for add_account_label (2935267344849993553) -->
     <skip />
-    <!-- no translation found for choose_account_text (6891230675141555481) -->
+    <!-- no translation found for choose_account_text (6303348737197849675) -->
     <skip />
     <!-- no translation found for add_account_button_label (3611982894853435874) -->
     <skip />
@@ -1356,7 +1708,7 @@
     <skip />
     <!-- no translation found for number_picker_decrement_button (2576606679160067262) -->
     <skip />
-    <!-- no translation found for number_picker_increment_scroll_mode (1343063395404990189) -->
+    <!-- no translation found for number_picker_increment_scroll_mode (3073101067441638428) -->
     <skip />
     <!-- no translation found for number_picker_increment_scroll_action (4628981789985093179) -->
     <skip />
@@ -1440,7 +1792,7 @@
     <skip />
     <!-- no translation found for description_target_unlock_tablet (3833195335629795055) -->
     <skip />
-    <!-- no translation found for keyboard_headset_required_to_hear_password (5913502399391940888) -->
+    <!-- no translation found for keyboard_headset_required_to_hear_password (7011927352267668657) -->
     <skip />
     <!-- no translation found for keyboard_password_character_no_headset (2859873770886153678) -->
     <skip />
@@ -1450,17 +1802,17 @@
     <skip />
     <!-- no translation found for action_menu_overflow_description (2295659037509008453) -->
     <skip />
-    <!-- no translation found for storage_internal (7556050805474115618) -->
+    <!-- no translation found for storage_internal (4891916833657929263) -->
     <skip />
-    <!-- no translation found for storage_sd_card (8921771478629812343) -->
+    <!-- no translation found for storage_sd_card (3282948861378286745) -->
     <skip />
     <!-- no translation found for storage_usb (3017954059538517278) -->
     <skip />
-    <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+    <!-- no translation found for extract_edit_menu_button (8940478730496610137) -->
     <skip />
     <!-- no translation found for data_usage_warning_title (1955638862122232342) -->
     <skip />
-    <!-- no translation found for data_usage_warning_body (7217480745540055170) -->
+    <!-- no translation found for data_usage_warning_body (2814673551471969954) -->
     <skip />
     <!-- no translation found for data_usage_3g_limit_title (7093334419518706686) -->
     <skip />
@@ -1470,7 +1822,7 @@
     <skip />
     <!-- no translation found for data_usage_wifi_limit_title (8992154736441284865) -->
     <skip />
-    <!-- no translation found for data_usage_limit_body (4313857592916426843) -->
+    <!-- no translation found for data_usage_limit_body (3317964706973601386) -->
     <skip />
     <!-- no translation found for data_usage_3g_limit_snoozed_title (7026739121138005231) -->
     <skip />
@@ -1480,11 +1832,11 @@
     <skip />
     <!-- no translation found for data_usage_wifi_limit_snoozed_title (8743856006384825974) -->
     <skip />
-    <!-- no translation found for data_usage_limit_snoozed_body (2932736326652880660) -->
+    <!-- no translation found for data_usage_limit_snoozed_body (7035490278298441767) -->
     <skip />
     <!-- no translation found for data_usage_restricted_title (5965157361036321914) -->
     <skip />
-    <!-- no translation found for data_usage_restricted_body (5087354814839059798) -->
+    <!-- no translation found for data_usage_restricted_body (6741521330997452990) -->
     <skip />
     <!-- no translation found for ssl_certificate (6510040486049237639) -->
     <skip />
@@ -1524,4 +1876,10 @@
     <skip />
     <!-- no translation found for list_delimeter (3975117572185494152) -->
     <skip />
+    <!-- no translation found for sending (3245653681008218030) -->
+    <skip />
+    <!-- no translation found for launchBrowserDefault (2057951947297614725) -->
+    <skip />
+    <!-- no translation found for SetupCallDefault (5834948469253758575) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index bc7f619..fe3687f 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite aplicaţiei să mute activităţile în prim-plan şi în fundal. Aplicaţiile rău intenţionate pot să apară forţat în prim-plan, fără ca dvs. să puteţi controla acest lucru."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"oprire aplicaţii care rulează"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite aplicaţiei să elimine sarcini şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setaţi compatibilitatea ecranului"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite aplicaţiei să controleze modul de compatibilitate a ecranului pentru alte aplicaţii. Aplicaţiile rău intenţionate pot afecta comportamentul altor aplicaţii."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"activare depanare aplicaţie"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite aplicaţiei să activeze depanarea pentru o altă aplicaţie. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a închide alte aplicaţii."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"modificare setări UI"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite aplicaţiei să verifice dacă un pachet poate fi instalat."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"conectare la un verificator de pachete"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite proprietarului să efectueze solicitări pentru verificatori de pachete. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"acces la porturi seriale"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite posesorului accesul la porturile serial utilizând API-ul SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Doriţi ca browserul să reţină această parolă?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nu acum"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Reţineţi"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Raportaţi"</string>
     <string name="wait" msgid="7147118217226317732">"Aşteptaţi"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă."\n\n"Doriţi să o închideţi?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Aplicaţie redirecţionată"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcţionează acum."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 1d71fd6..55468a0 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Приложение сможет перемещать задачи в режим активного или фонового выполнения. Вредоносные программы смогут переводить себя в активный режим без вашего ведома."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"остановка запущенных приложений"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Приложение сможет удалять задачи и собственные программы. Вредоносное ПО при этом сможет нарушать работу других приложений."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Установка режима совместимости"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Приложение сможет управлять режимом совместимости экрана других приложений. Вредоносное ПО может привести к сбоям в работе других программ."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"включение отладки приложений"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Приложение сможет включать отладку для другой программы. Вредоносное ПО сможет таким образом останавливать работу других приложений."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"изменять настройки пользовательского интерфейса"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Приложение сможет проверять возможность установки пакетов."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"связываться с верификатором пакетов"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Приложение сможет запрашивать проверку пакетов. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"доступ к последовательным портам"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Открыть владельцу доступ к последовательным портам с помощью SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Вы хотите, чтобы браузер запомнил этот пароль?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не сейчас"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запомнить"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"ОК"</string>
     <string name="report" msgid="4060218260984795706">"Отзыв"</string>
     <string name="wait" msgid="7147118217226317732">"Подождать"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница не отвечает."\n\n"Закрыть ее?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Приложение перенаправлено"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> выполняется."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Изначально было запущено приложение <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index cb2e764..69bc4b8 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Umožňuje aplikácii presúvať úlohy do popredia a pozadia. Škodlivé aplikácie sa môžu pretlačiť do popredia bez vášho vedomia."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zastaviť spustené aplikácie"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikácii odstrániť úlohy a ukončiť ich aplikácie. Škodlivé aplikácie môžu narušiť správanie iných aplikácií."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"povoliť ladenie aplikácií"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Umožňuje aplikácii zapnúť ladenie inej aplikácie. Škodlivé aplikácie môžu pomocou tohto nastavenia ukončiť iné aplikácie."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmeny vašich nastavení používateľského rozhrania"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikácii overiť, či je možné balík nainštalovať."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"naviazať na overovateľa balíka"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteľovi podávať žiadosti o overenie balíkov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"prístup k sériovým portom"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Držiteľa oprávňuje na prístup k sériovým portom pomocou rozhrania API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prehliadač zapamätal toto heslo?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Teraz nie"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapamätať"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Prehľad"</string>
     <string name="wait" msgid="7147118217226317732">"Čakajte"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje."\n\n"Chcete ju zavrieť?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Presmerovaná aplikácia"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Je spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Pôvodne bola spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5e7c136..dfedb9a 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Programu omogoča premikanje opravil v ospredje in ozadje. Zlonamerni programi se lahko brez vašega nadzora vsilijo v ospredje."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"ustavitev programov, ki se izvajajo"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Programu omogoča odstranjevanje opravil in zapiranje njihovih programov. Zlonamerni programi lahko motijo delovanje drugih programov."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavitev združljivosti zaslona"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Programu omogoča nadzor združljivostnega načina zaslona drugih programov. Zlonamerni programi lahko prekinejo delovanje drugih programov."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"omogočanje iskanja in odpravljanja napak v programu"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Programu omogoča vklop funkcije za odpravljanje napak za drug program. Zlonamerni programi lahko to uporabijo za zapiranje drugih programov."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"spreminjanje nastavitev UV"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Programu omogoča, da preveri, ali je paket mogoče namestiti."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"poveži s preverjanjem paketov"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Imetniku omogoča zahtevanje preverjanja paketov. Tega nikoli ni treba uporabiti za navadne programe."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"dostop do serijskih vrat"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Imetniku omogoča, da z API-jem za SerialManager dostopa do serijskih vrat."</string>
     <string name="save_password_message" msgid="767344687139195790">"Ali želite, da si brskalnik zapomni to geslo?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ne zdaj"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapomni si"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"V redu"</string>
     <string name="report" msgid="4060218260984795706">"Poročaj"</string>
     <string name="wait" msgid="7147118217226317732">"Čakaj"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Stran se ne odziva."\n" "\n"Ali jo želite zapreti?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Program preusmerjen"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvaja."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Prvotno je bil zagnan program <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index bea78ce..2a2104f 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -50,7 +50,7 @@
     <string name="invalidPuk" msgid="8761456210898036513">"Унесите PUK који се састоји од 8 цифара или више."</string>
     <string name="needPuk" msgid="919668385956251611">"SIM картица је закључана PUK кодом. Унесите PUK кôд да бисте је откључали."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Унесите PUK2 да бисте деблокирали SIM картицу."</string>
-    <string name="ClipMmi" msgid="6952821216480289285">"Долазећи ИД позиваоца"</string>
+    <string name="ClipMmi" msgid="6952821216480289285">"Долазни ИД позиваоца"</string>
     <string name="ClirMmi" msgid="7784673673446833091">"Одлазни ИД позиваоца"</string>
     <string name="CfMmi" msgid="5123218989141573515">"Преусмеравање позива"</string>
     <string name="CwMmi" msgid="9129678056795016867">"Позив на чекању"</string>
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дозвољава апликацији да премешта задатке у први план и у позадину. Злонамерне апликације могу на тај начин да принудно пређу у први план без ваше контроле."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"заустављање покренутих апликација"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозвољава апликацији да уклања задатке и уништава њихове апликације. Злонамерне апликације могу да поремете понашање других апликација."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"подешавање компатибилности екрана"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Дозвољава апликацији да контролише режим компатибилности екрана других апликација. Злонамерне апликације могу да угрозе понашање других апликација."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"омогућавање отклањања грешака у апликацији"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дозвољава апликацији да укључи уклањање грешака за другу апликацију. Злонамерне апликације могу то да искористе за онемогућавање других апликација."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"промена подешавања корисничког интерфејса"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозвољава апликацији да верификује да ли је пакет могуће инсталирати."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обавезивање на верификатор пакета"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Омогућава да власник упућује захтеве верификаторима пакета. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"приступ серијским портовима"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Омогућава власнику да приступи серијским портовима помоћу SerialManager API-ја."</string>
     <string name="save_password_message" msgid="767344687139195790">"Желите ли да прегледач запамти ову лозинку?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не сада"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запамти"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"Потврди"</string>
     <string name="report" msgid="4060218260984795706">"Пријави"</string>
     <string name="wait" msgid="7147118217226317732">"Сачекај"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница је престала да се одазива."\n\n" Да ли желите да је затворите?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Апликација је преусмерена"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је сада покренута."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Првобитно је покренута апликација <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bc59298..0067a12 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Tillåter att appen flyttar uppgifter till förgrunden eller bakgrunden. Skadliga appar kan tvinga sig till förgrunden utan att du kan styra det."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"avsluta appar som körs"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillåter att appen tar bort uppgifter och avslutar appar. Skadliga appar kan störa funktionen i andra appar."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ange skärmkompatibilitet"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Tillåter att appen styr skärmkompatibilitetsläget i andra appar. Skadliga appar kan störa andra appars funktion."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivera felsökning av appar"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Tillåter att appen aktiverar felsökning för en annan app. Skadliga appar kan använda detta för att avsluta andra appar."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"ändra dina gränssnittsinställningar"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillåter att appen kontrollerar om ett paket går att installera."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"binda till en paketverifierare"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillåter att innehavaren skickar förfrågningar till paketverifierare. Det ska inte behövas för vanliga appar."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"åtkomst till serieportar"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Innebär att innehavaren får åtkomst till serieportar med programmeringsgränssnittet för SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Vill du att webbläsaren ska komma ihåg lösenordet?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Inte nu"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Kom ihåg"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Rapportera"</string>
     <string name="wait" msgid="7147118217226317732">"Vänta"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Sidan har slutat svara."\n\n"Vill du stänga sidan?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Appen omdirigeras"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> körs."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> startades först."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 5077d1f..369853c 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Inaruhusu programu kusongesha kazi kwenye mandhari-mbele na mandhari-nyuma. Programu hasidi zinaweza kujilazimisha mbele bila udhibiti wako."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"Komesha programu zinazoendeshwa"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Huruhusu programu kuondoa majukumu na kuua programu zao. Programu hasidi zinaweza kutatiza tabia ya programu zingine."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"weka utangamano wa skrini"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Huruhusu programu kudhibiti hali ya utangamano wa skrini ya programu zingine. Programu hasidi zinaweza kuvunja mwenendo wa programu zingine."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"wezesha utatuaji wa programu"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Huruhusu programu kuwasha kueua cha programu nyingine. Programu hasidi huenda zikatumia hii ili kuua programu nyingine."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"badilisha mipangilio yako ya onyesho"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Inaruhusu programu kuthibitisha kuwa furushi linaweza kusakinishwa."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Funga kwa kithibitishaji cha furushi"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Inaruhusu mmiliki kutuma maombi ya vibainishi furushi. Kamwe hazitahitajika kwa programu za kawaida."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"kituo tambulishi cha ufikivu"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Inaruhusu mmiliki kufikia vituo tambulishi kwa kutumia KisimamiziTambulishi cha API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Unataka kuvinjari ili ukumbuke nenosiri hili?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Si Sasa"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"Sawa"</string>
     <string name="report" msgid="4060218260984795706">"Ripoti"</string>
     <string name="wait" msgid="7147118217226317732">"Subiri"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Ukurasa umekwama. "\n" "\n" Je, unataka kuufunga?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Programu imeelekezwa kwingine"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>inaendesha sasa."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilizinduliwa mwanzoni."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 0babb00..debe568 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"อนุญาตให้แอปพลิเคชันย้ายงานไปยังส่วนหน้าและพื้นหลัง แอปพลิเคชันที่เป็นอันตรายอาจบังคับตัวเองให้ไปที่ส่วนหน้าโดยไม่มีการควบคุมจากคุณ"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"หยุดแอปพลิเคชันที่ทำงานอยู่"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"อนุญาตให้แอปพลิเคชันลบงานออกและยุติแอปพลิเคชันต่างๆ ของงานนั้น แอปพลิเคชันที่เป็นอันตรายอาจทำให้แอปพลิเคชันอื่นๆ ทำงานได้ไม่ถูกต้อง"</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ตั้งค่าความเข้ากันได้ของหน้าจอ"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"อนุญาตให้แอปพลิเคชันควบคุมโหมดความเข้ากันได้ของหน้าจอของแอปพลิเคชันอื่น แอปพลิเคชันที่เป็นอันตรายอาจทำให้แอปพลิเคชันอื่นทำงานผิดพลาด"</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"เปิดใช้งานการแก้ไขบกพร่องของแอปพลิเคชัน"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"อนุญาตให้แอปพลิเคชันเปิดการแก้ไขข้อบกพร่องสำหรับแอปพลิเคชันอื่น แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติการทำงานของแอปพลิเคชันอื่นๆ ได้"</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"เปลี่ยนการตั้งค่า UI ของคุณ"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพคเกจสามารถติดตั้งได้หรือไม่"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพคเกจ"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพคเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
     <string name="save_password_message" msgid="767344687139195790">"คุณต้องการให้เบราว์เซอร์จำรหัสผ่านนี้หรือไม่"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"ยังไม่ใช้งานขณะนี้"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"จำไว้"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"ตกลง"</string>
     <string name="report" msgid="4060218260984795706">"รายงาน"</string>
     <string name="wait" msgid="7147118217226317732">"รอ"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"หน้าเว็บนี้ไม่ตอบสนอง"\n\n"คุณต้องการปิดหรือไม่"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"แอปฯ ที่เปลี่ยนเส้นทาง"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังทำงานอยู่ในขณะนี้"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> เปิดใช้ไว้แล้ว"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index b31fbf7..e74e309 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Pinapayagan ang app na ilipat ang mga gawain sa foreground at background. Maaaring puwersahin ng nakakahamak na apps ang mga sarili nito sa harapan nang wala ang iyong pagkontrol."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"ihinto ang pagpapatakbo ng apps"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Pinapayagan ang app na mag-alis ng mga gawain at i-off ang apps nito. Maaaring maantala ng nakakahamak na apps ang pagkilos ng iba pang apps."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"itakda ang pagkakatugma ng screen"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pinapayagan ang app na kontrolin ang mode ng pagkakatugma ng screen ng iba pang mga application. Maaaring sirain ng mga nakakahamak na application ang pag-uugali ng iba pang mga application."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"paganahin ang pag-debug ng app"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pinapayagan ang app na i-on ang pag-debug para sa isa pang app. Maaari itong gamitin ng nakakahamak na apps upang i-off ang iba pang apps."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"baguhin ang iyong mga setting ng UI"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pinapayagan ang app na i-verify kung ang isang package ay nai-install."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sumailalim sa taga-verify ng package"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pinapayagan ang may-ari na gumawa ng mga kahilingan ng mga taga-verify ng package. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"mag-access sa mga serial port"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Binibigyang-daan ang may-ari na mag-access ng mga serial port gamit ang SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Gusto mo bang tandaan ng browser ang password na ito?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Hindi ngayon"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Tandaan"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Ulat"</string>
     <string name="wait" msgid="7147118217226317732">"Maghintay"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Hindi na tumutugon ang pahina."\n\n"Nais mo ba itong isara?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Na-redirect ang app"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Tumatakbo na ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Orihinal na nalunsad ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ebade95..20d3e15 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Uygulamaya, görevleri ön plana ve arka plana taşıma izni verir. Kötü amaçlı uygulamalar kendilerini sizin denetiminiz dışında ön plana taşıyabilir."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"çalışan uygulamaları durdur"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Uygulamaya, görevleri kaldırma ve bunlara ait uygulamaları kapatma izni verir. Kötü amaçlı uygulamalar diğer uygulamaların çalışmasını bozabilir."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"uygulama hata ayıklamayı etkinleştir"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Uygulamaya, başka bir uygulama için hata ayıklamayı açma izni verir. Kötü amaçlı uygulamalar diğer uygulamaları kaldırmak için bunu kullanabilir."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"kullanıcı arayüzü ayarlarınızı değiştirin"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Uygulamaya, bir paketin yüklenebilir olduğunu doğrulama izni verir."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"paket doğrulayıcıya bağlan"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cihazın sahibine, paket doğrulayıcıları için istek yapma izni verir. Normal uygulamalar için gerekli olmaz."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"seri bağlantı noktalarına eriş"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"İzin sahibinin, SerialManager API\'sını kullanarak seri bağlantı noktalarına erişmesine olanak sağlar."</string>
     <string name="save_password_message" msgid="767344687139195790">"Tarayıcının bu şifreyi anımsamasını istiyor musunuz?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Şimdi değil"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Anımsa"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"Tamam"</string>
     <string name="report" msgid="4060218260984795706">"Bildir"</string>
     <string name="wait" msgid="7147118217226317732">"Bekle"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Sayfa yanıt vermiyor."\n\n"Kapatmak ister misiniz?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Uygulama yönlendirildi"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> şimdi çalışıyor."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"İlk olarak <xliff:g id="APP_NAME">%1$s</xliff:g> başlatıldı."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index bc5456b..9d049cf 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дозволяє програмі переміщувати завдання в активні чи фонові вікна. Шкідливі програми можуть примусово ставати активними без вашого відома."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"зупиняти запущені програми"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозволяє програмі видаляти завдання та примусово припиняти роботу відповідних програм. Шкідливі програми можуть переривати роботу інших програм."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"установити сумісність екрана"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Дозволяє програмі контролювати режим сумісності екрана інших програм. Шкідливі програми можуть переривати роботу інших програм."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"вмикати налагодження програми"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дозволяє програмі вмикати налагодження для іншої програми. Шкідливі програми можуть використовувати це для примусового припинення роботи інших програм."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"змін. налашт. інтерф. кор."</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозволяє програмі перевіряти можливість встановлення пакета."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"прив’язуватися до програми перевірки пакетів"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дозволяє власникові робити запити на програми перевірки пакетів. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"отримувати доступ до послідовних портів"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Дозволяє власнику отримувати доступ до послідовних портів за допомогою API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Хочете, щоб переглядач запам\'ятав цей пароль?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не зараз"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запам\'ятати"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Повідом."</string>
     <string name="wait" msgid="7147118217226317732">"Чекати"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Сторінка не відповідає."\n\n"Закрити її?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Програму переадресовано"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"Зараз працює <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"Спочатку було запущено <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 177c474..8166606 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -215,6 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Cho phép ứng dụng di chuyển công việc sang nền trước và nền sau. Ứng dụng độc hại có thể tự hiển thị ở nền trước mà không chịu sự kiểm soát của bạn."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"dừng các ứng dụng đang chạy"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Cho phép ứng dụng xóa công việc và loại bỏ các ứng dụng của chúng. Ứng dụng độc hại có thể làm gián đoạn hoạt động của các ứng dụng khác."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"đặt độ tương thích màn hình"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Cho phép ứng dụng kiểm soát chế độ tương thích màn hình của ứng dụng khác. Các ứng dụng độc hại có thể phá vỡ hoạt động của các ứng dụng khác."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"bật gỡ lỗi ứng dụng"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Cho phép ứng dụng bật gỡ lỗi cho một ứng dụng khác. Ứng dụng độc hại có thể sử dụng quyền này để loại bỏ những ứng dụng khác."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"thay đổi cài đặt giao diện người dùng của bạn"</string>
@@ -760,6 +762,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Cho phép ứng dụng xác minh gói có thể cài đặt."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"liên kết với trình xác minh gói"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cho phép chủ sở hữu yêu cầu trình xác minh gói. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"truy cập cổng nối tiếp"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Cho phép chủ sở hữu truy cập cổng nối tiếp sử dụng API SerialManager."</string>
     <string name="save_password_message" msgid="767344687139195790">"Bạn có muốn trình duyệt nhớ mật khẩu này không?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Không phải bây giờ"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Nhớ"</string>
@@ -915,6 +919,7 @@
     <string name="force_close" msgid="8346072094521265605">"OK"</string>
     <string name="report" msgid="4060218260984795706">"Báo cáo"</string>
     <string name="wait" msgid="7147118217226317732">"Đợi"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Trang không phản hồi."\n\n"Bạn có muốn đóng trang không?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Đã chuyển hướng ứng dụng"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện đang chạy."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> được khởi chạy trước tiên."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b682eac..1065183 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"允许应用程序将任务移动到前台和后台。恶意应用程序可能会不受您的控制,强行让自己处于前台。"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"停止正在运行的应用程序"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"允许该应用程序删除任务并终止这些任务的应用程序。恶意应用程序可以籍此影响其他应用程序的行为。"</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"启用应用程序调试"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"允许该应用程序对其他应用程序启用调试。恶意应用程序可以籍此终止其他的应用程序。"</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"更改用户界面设置"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允许应用程序验证程序包是否可以安装。"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"绑定到软件包验证程序"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允许用户请求使用程序包验证程序。普通应用程序绝不需要此权限。"</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"访问串行端口"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"允许持有人使用 SerialManager API 访问串行端口。"</string>
     <string name="save_password_message" msgid="767344687139195790">"是否希望浏览器记住此密码?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"暂不保存"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"记住"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"确定"</string>
     <string name="report" msgid="4060218260984795706">"报告"</string>
     <string name="wait" msgid="7147118217226317732">"等待"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"该网页已无响应。"\n\n"要将其关闭吗?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"应用程序已重定向"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前正在运行。"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>已启动。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 0928de8..659c2de 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"允許應用程式將工作移至前景或背景。請注意,惡意應用程式可能利用此功能自行移動至前景。"</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"停止執行中的應用程式"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"允許應用程式移除工作並終止執行工作的應用程式。請注意,惡意應用程式可能利用此功能干擾其他應用程式的行為。"</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"啟用應用程式偵錯"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"允許應用程式為其他程式開啟偵錯功能。提醒您,惡意應用程式可能會利用這個功能終止其他應用程式。"</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介面設定"</string>
@@ -697,7 +701,7 @@
     <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"您嘗試解除這支手機的鎖定已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次,手機現在將恢復原廠設定。"</string>
     <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"忘記解鎖圖形?"</string>
-    <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"解除封鎖帳戶"</string>
+    <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"帳戶解鎖"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"圖形嘗試次數過多"</string>
     <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"如要解除鎖定,請使用 Google 帳戶登入。"</string>
     <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"使用者名稱 (電子郵件)"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允許應用程式驗證是否可安裝特定套件。"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"繫結至套件驗證程序"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允許應用程式要求驗證套件 (一般應用程式不需使用)。"</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"存取序列埠"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"允許應用程式使用 SerialManager API 存取序列埠。"</string>
     <string name="save_password_message" msgid="767344687139195790">"是否記住此密碼?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"現在不要"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"記住"</string>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"確定"</string>
     <string name="report" msgid="4060218260984795706">"回報"</string>
     <string name="wait" msgid="7147118217226317732">"等待"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"網頁沒有回應。"\n\n"您要結束嗎?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"應用程式已重新導向"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在正在執行。"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」原先已啟動。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index fc01c1d..84f4319 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -215,6 +215,10 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ivumela insiza ukuthi ihambise izenzo ziye ngaphambili kanye nasemumva. Izinsiza ezinobungozi zingaziphoqelela ukuth iziye phambili ngaphandle kokulawula kwakho."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinsiza ezisebenzayo"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi insiza isuse okumele kwenziwe ibulale nezinsiza zakho. Izinsiza eziwubungozi zingaphazamisa ukusebenza kwezinye izinsiza."</string>
+    <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
+    <skip />
+    <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
+    <skip />
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"vumela insiza ilungise inkinga"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ivumela insiza ukuthi ivule uhlelo lokulungisa lwenye insiza. Izinsiza ezinobungozi zingasebenzisa lokhu ukubulala ezinye izinsiza."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"shintsha izilungiselelo zakho ze-UI"</string>
@@ -760,6 +764,8 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ivumela ukuthi isisetshenziswa siqinisekise ukuthi ngabe iphakheji iyafakeka."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bopha okokuqinisekisa iphakheji"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ivumela umnikazi ukuthi enze izicelo zezinsiza eziqinisekisa iphakheji. Akumele kudingeke ekusetshenzisweni okujwayelekile."</string>
+    <string name="permlab_serialPort" msgid="546083327654631076">"finyelela kuma- serial port"</string>
+    <string name="permdesc_serialPort" msgid="2991639985224598193">"Ivumela umnikai ukuthi athole inombolo ye-serial ukue angene kwiindawo ze-serial esebenzisa i-SerialManager API."</string>
     <string name="save_password_message" msgid="767344687139195790">"Ingabe ufuna ukuba isiphequluli sikhumbule lephasiwedi?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Hha yi manje"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Khumbula"</string>
@@ -785,7 +791,7 @@
   </plurals>
   <plurals name="num_minutes_ago">
     <item quantity="one" msgid="3306787433088810191">"iminithi elingu-1 edlule"</item>
-    <item quantity="other" msgid="2176942008915455116">"amaminithi angu-<xliff:g id="COUNT">%d</xliff:g> adlule.."</item>
+    <item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> amaminithi adlule.."</item>
   </plurals>
   <plurals name="num_hours_ago">
     <item quantity="one" msgid="9150797944610821849">"ihora elingu-1 elidlule"</item>
@@ -822,7 +828,7 @@
   </plurals>
   <plurals name="abbrev_num_minutes_ago">
     <item quantity="one" msgid="6361490147113871545">"iminithi elingu-1 edlule"</item>
-    <item quantity="other" msgid="851164968597150710">"amaminithi angu-<xliff:g id="COUNT">%d</xliff:g> adlule"</item>
+    <item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> amaminithi adlule"</item>
   </plurals>
   <plurals name="abbrev_num_hours_ago">
     <item quantity="one" msgid="4796212039724722116">"ihora elingu-1 elidlule"</item>
@@ -915,6 +921,7 @@
     <string name="force_close" msgid="8346072094521265605">"KULUNGILE"</string>
     <string name="report" msgid="4060218260984795706">"Umbiko"</string>
     <string name="wait" msgid="7147118217226317732">"Linda"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"Leli khasi alisaphenduli."\n\n"Ingabe ufuna ukulivala na?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Insiza idluliselwe phambili"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> iyasebenza."</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> iqalisiwe."</string>
@@ -1110,7 +1117,7 @@
     <string name="no_matches" msgid="8129421908915840737">"Akukho okufanayo"</string>
     <string name="find_on_page" msgid="1946799233822820384">"Thola ekhasini"</string>
   <plurals name="matches_found">
-    <item quantity="one" msgid="8167147081136579439">"okufanayo okungu-1"</item>
+    <item quantity="one" msgid="8167147081136579439">"1 okufanayo"</item>
     <item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> ku-<xliff:g id="TOTAL">%d</xliff:g>"</item>
   </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Kwenziwe"</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index f9e1f5b..ce734fc 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -22,19 +22,9 @@
     <!-- Do not translate. These are all of the drawable resources that should be preloaded by
          the zygote process before it starts forking application processes. -->
     <array name="preloaded_drawables">
-       <item>@drawable/spinner_black_16</item>
-       <item>@drawable/spinner_black_20</item>
-       <item>@drawable/spinner_black_48</item>
-       <item>@drawable/spinner_black_76</item>
-       <item>@drawable/spinner_white_16</item>
-       <item>@drawable/spinner_white_48</item>
-       <item>@drawable/spinner_white_76</item>
-       <item>@drawable/toast_frame</item>
        <item>@drawable/toast_frame_holo</item>
-       <item>@drawable/btn_check_on_selected</item>
        <item>@drawable/btn_check_on_pressed_holo_light</item>
        <item>@drawable/btn_check_on_pressed_holo_dark</item>
-       <item>@drawable/btn_check_on_pressed</item>
        <item>@drawable/btn_check_on_holo_light</item>
        <item>@drawable/btn_check_on_holo_dark</item>
        <item>@drawable/btn_check_on_focused_holo_light</item>
@@ -43,13 +33,8 @@
        <item>@drawable/btn_check_on_disabled_holo_dark</item>
        <item>@drawable/btn_check_on_disabled_focused_holo_light</item>
        <item>@drawable/btn_check_on_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_check_on_disable_focused</item>
-       <item>@drawable/btn_check_on_disable</item>
-       <item>@drawable/btn_check_on</item>
-       <item>@drawable/btn_check_off_selected</item>
        <item>@drawable/btn_check_off_pressed_holo_light</item>
        <item>@drawable/btn_check_off_pressed_holo_dark</item>
-       <item>@drawable/btn_check_off_pressed</item>
        <item>@drawable/btn_check_off_holo_light</item>
        <item>@drawable/btn_check_off_holo_dark</item>
        <item>@drawable/btn_check_off_focused_holo_light</item>
@@ -58,16 +43,10 @@
        <item>@drawable/btn_check_off_disabled_holo_dark</item>
        <item>@drawable/btn_check_off_disabled_focused_holo_light</item>
        <item>@drawable/btn_check_off_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_check_off_disable_focused</item>
-       <item>@drawable/btn_check_off_disable</item>
-       <item>@drawable/btn_check_label_background</item>
        <item>@drawable/btn_check_holo_light</item>
        <item>@drawable/btn_check_holo_dark</item>
-       <item>@drawable/btn_check</item>
-       <item>@drawable/btn_radio_on_selected</item>
        <item>@drawable/btn_radio_on_pressed_holo_light</item>
        <item>@drawable/btn_radio_on_pressed_holo_dark</item>
-       <item>@drawable/btn_radio_on_pressed</item>
        <item>@drawable/btn_radio_on_holo_light</item>
        <item>@drawable/btn_radio_on_holo_dark</item>
        <item>@drawable/btn_radio_on_focused_holo_light</item>
@@ -76,11 +55,8 @@
        <item>@drawable/btn_radio_on_disabled_holo_dark</item>
        <item>@drawable/btn_radio_on_disabled_focused_holo_light</item>
        <item>@drawable/btn_radio_on_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_radio_on</item>
-       <item>@drawable/btn_radio_off_selected</item>
        <item>@drawable/btn_radio_off_pressed_holo_light</item>
        <item>@drawable/btn_radio_off_pressed_holo_dark</item>
-       <item>@drawable/btn_radio_off_pressed</item>
        <item>@drawable/btn_radio_off_holo_light</item>
        <item>@drawable/btn_radio_off_holo_dark</item>
        <item>@drawable/btn_radio_off_focused_holo_light</item>
@@ -89,23 +65,10 @@
        <item>@drawable/btn_radio_off_disabled_holo_dark</item>
        <item>@drawable/btn_radio_off_disabled_focused_holo_light</item>
        <item>@drawable/btn_radio_off_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_radio_label_background</item>
-       <item>@drawable/btn_radio</item>
-       <item>@drawable/btn_default_transparent_normal</item>
-       <item>@drawable/btn_default_small_selected</item>
-       <item>@drawable/btn_default_small_pressed</item>
-       <item>@drawable/btn_default_small_normal_disable_focused</item>
-       <item>@drawable/btn_default_small_normal_disable</item>
-       <item>@drawable/btn_default_small_normal</item>
-       <item>@drawable/btn_default_selected</item>
        <item>@drawable/btn_default_pressed_holo_light</item>
        <item>@drawable/btn_default_pressed_holo_dark</item>
-       <item>@drawable/btn_default_pressed</item>
        <item>@drawable/btn_default_normal_holo_light</item>
        <item>@drawable/btn_default_normal_holo_dark</item>
-       <item>@drawable/btn_default_normal_disable_focused</item>
-       <item>@drawable/btn_default_normal_disable</item>
-       <item>@drawable/btn_default_normal</item>
        <item>@drawable/btn_default_focused_holo_light</item>
        <item>@drawable/btn_default_focused_holo_dark</item>
        <item>@drawable/btn_default_disabled_holo_light</item>
@@ -114,24 +77,6 @@
        <item>@drawable/btn_default_disabled_focused_holo_dark</item>
        <item>@drawable/btn_default_holo_dark</item>
        <item>@drawable/btn_default_holo_light</item>
-       <item>@drawable/btn_default</item>
-       <item>@drawable/btn_default_small</item>
-       <item>@drawable/btn_dropdown_disabled</item>
-       <item>@drawable/btn_dropdown_disabled_focused</item>
-       <item>@drawable/btn_dropdown_normal</item>
-       <item>@drawable/btn_dropdown_pressed</item>
-       <item>@drawable/btn_dropdown_selected</item>
-       <item>@drawable/btn_star_label_background</item>
-       <item>@drawable/btn_star_big_off</item>
-       <item>@drawable/btn_star_big_on</item>
-       <item>@drawable/btn_star_big_on_disable</item>
-       <item>@drawable/btn_star_big_off_disable</item>
-       <item>@drawable/btn_star_big_on_pressed</item>
-       <item>@drawable/btn_star_big_off_pressed</item>
-       <item>@drawable/btn_star_big_on_selected</item>
-       <item>@drawable/btn_star_big_off_selected</item>
-       <item>@drawable/btn_star_big_on_disable_focused</item>
-       <item>@drawable/btn_star_big_off_disable_focused</item>
        <item>@drawable/btn_star_off_normal_holo_light</item>
        <item>@drawable/btn_star_on_normal_holo_light</item>
        <item>@drawable/btn_star_on_disabled_holo_light</item>
@@ -154,7 +99,6 @@
        <item>@drawable/btn_star_on_disabled_focused_holo_dark</item>
        <item>@drawable/btn_star_off_disabled_focused_holo_dark</item>
        <item>@drawable/btn_star_holo_dark</item>
-       <item>@drawable/btn_star</item>
        <item>@drawable/btn_toggle_on_pressed_holo_light</item>
        <item>@drawable/btn_toggle_on_pressed_holo_dark</item>
        <item>@drawable/btn_toggle_on_normal_holo_light</item>
@@ -165,7 +109,6 @@
        <item>@drawable/btn_toggle_on_disabled_holo_dark</item>
        <item>@drawable/btn_toggle_on_disabled_focused_holo_light</item>
        <item>@drawable/btn_toggle_on_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_toggle_on</item>
        <item>@drawable/btn_toggle_off_pressed_holo_light</item>
        <item>@drawable/btn_toggle_off_pressed_holo_dark</item>
        <item>@drawable/btn_toggle_off_normal_holo_light</item>
@@ -176,23 +119,10 @@
        <item>@drawable/btn_toggle_off_disabled_holo_dark</item>
        <item>@drawable/btn_toggle_off_disabled_focused_holo_light</item>
        <item>@drawable/btn_toggle_off_disabled_focused_holo_dark</item>
-       <item>@drawable/btn_toggle_off</item>
        <item>@drawable/btn_toggle_holo_light</item>
        <item>@drawable/btn_toggle_holo_dark</item>
-       <item>@drawable/btn_toggle</item>
-       <item>@drawable/btn_toggle_bg</item>
-       <item>@drawable/btn_dropdown</item>
-       <item>@drawable/btn_dropdown</item>
-       <item>@drawable/light_header_dither</item>
-       <item>@drawable/divider_horizontal_textfield</item>
-       <item>@drawable/divider_horizontal_dark_opaque</item>
-       <item>@drawable/divider_horizontal_dark</item>
-       <item>@drawable/divider_horizontal_bright_opaque</item>
-       <item>@drawable/divider_horizontal_bright</item>
-       <item>@drawable/divider_vertical_dark</item>
        <item>@drawable/edit_text_holo_light</item>
        <item>@drawable/edit_text_holo_dark</item>
-       <item>@drawable/edit_text</item>
        <item>@drawable/text_cursor_holo_light</item>
        <item>@drawable/text_cursor_holo_dark</item>
        <item>@drawable/text_select_handle_left</item>
@@ -200,70 +130,45 @@
        <item>@drawable/text_edit_paste_window</item>
        <item>@drawable/expander_close_holo_dark</item>
        <item>@drawable/expander_close_holo_light</item>
-       <item>@drawable/expander_ic_maximized</item>
-       <item>@drawable/expander_ic_minimized</item>
-       <item>@drawable/expander_group</item>
        <item>@drawable/expander_group_holo_dark</item>
        <item>@drawable/expander_group_holo_light</item>
-       <item>@drawable/list_selector_background</item>
-       <item>@drawable/list_selector_background_light</item>
-       <item>@drawable/list_selector_background_longpress</item>
-       <item>@drawable/list_selector_background_longpress_light</item>
-       <item>@drawable/list_selector_background_pressed</item>
-       <item>@drawable/list_selector_background_pressed_light</item>
-       <item>@drawable/list_selector_background_selected</item>
        <item>@drawable/list_selector_holo_dark</item>
        <item>@drawable/list_selector_holo_light</item>
        <item>@drawable/list_section_divider_holo_light</item>
        <item>@drawable/list_section_divider_holo_dark</item>
-       <item>@drawable/menu_background</item>
-       <item>@drawable/menu_background_fill_parent_width</item>
        <item>@drawable/menu_hardkey_panel_holo_dark</item>
        <item>@drawable/menu_hardkey_panel_holo_light</item>
        <item>@drawable/menu_submenu_background</item>
-       <item>@drawable/menu_selector</item>
        <item>@drawable/menu_dropdown_panel_holo_light</item>
        <item>@drawable/menu_dropdown_panel_holo_dark</item>
        <item>@drawable/overscroll_edge</item>
        <item>@drawable/overscroll_glow</item>
-       <item>@drawable/panel_background</item>
-       <item>@drawable/popup_bottom_bright</item>
-       <item>@drawable/popup_bottom_dark</item>
-       <item>@drawable/popup_bottom_medium</item>
-       <item>@drawable/popup_center_bright</item>
-       <item>@drawable/popup_center_dark</item>
-       <item>@drawable/popup_center_medium</item>
-       <item>@drawable/popup_full_bright</item>
-       <item>@drawable/popup_full_dark</item>
-       <item>@drawable/popup_top_bright</item>
-       <item>@drawable/popup_top_dark</item>
        <item>@drawable/popup_inline_error_above_holo_dark</item>
        <item>@drawable/popup_inline_error_above_holo_light</item>
        <item>@drawable/popup_inline_error_holo_dark</item>
        <item>@drawable/popup_inline_error_holo_light</item>
+       <item>@drawable/spinner_16_outer_holo</item>
+       <item>@drawable/spinner_16_inner_holo</item>
+       <item>@drawable/spinner_48_outer_holo</item>
+       <item>@drawable/spinner_48_inner_holo</item>
+       <item>@drawable/spinner_76_outer_holo</item>
+       <item>@drawable/spinner_76_inner_holo</item>
        <item>@drawable/progress_bg_holo_dark</item>
        <item>@drawable/progress_bg_holo_light</item>
-       <item>@drawable/progress_horizontal</item>
        <item>@drawable/progress_horizontal_holo_dark</item>
        <item>@drawable/progress_horizontal_holo_light</item>
-       <item>@drawable/progress_indeterminate_horizontal</item>
        <item>@drawable/progress_indeterminate_horizontal_holo</item>
-       <item>@drawable/progress_large</item>
        <item>@drawable/progress_large_holo</item>
-       <item>@drawable/progress_large_white</item>
-       <item>@drawable/progress_medium</item>
        <item>@drawable/progress_medium_holo</item>
-       <item>@drawable/progress_medium_white</item>
        <item>@drawable/progress_primary_holo_dark</item>
        <item>@drawable/progress_primary_holo_light</item>
        <item>@drawable/progress_secondary_holo_dark</item>
        <item>@drawable/progress_secondary_holo_light</item>
-       <item>@drawable/progress_small</item>
        <item>@drawable/progress_small_holo</item>
-       <item>@drawable/progress_small_titlebar</item>
-       <item>@drawable/progress_small_white</item>
        <item>@drawable/scrubber_progress_horizontal_holo_dark</item>
        <item>@drawable/scrubber_progress_horizontal_holo_light</item>
+       <item>@drawable/background_holo_light</item>
+       <item>@drawable/background_holo_dark</item>
        <item>@drawable/screen_background_dark</item>
        <item>@drawable/screen_background_dark_transparent</item>
        <item>@drawable/screen_background_light</item>
@@ -272,8 +177,6 @@
        <item>@drawable/screen_background_selector_light</item>
        <item>@drawable/scrollbar_handle_holo_dark</item>
        <item>@drawable/scrollbar_handle_holo_light</item>
-       <item>@drawable/scrollbar_handle_horizontal</item>
-       <item>@drawable/scrollbar_handle_vertical</item>
        <item>@drawable/spinner_background_holo_dark</item>
        <item>@drawable/spinner_background_holo_light</item>
        <item>@drawable/spinner_ab_default_holo_dark</item>
@@ -290,9 +193,6 @@
        <item>@drawable/spinner_default_holo_light</item>
        <item>@drawable/spinner_disabled_holo_dark</item>
        <item>@drawable/spinner_disabled_holo_light</item>
-       <item>@drawable/spinner_dropdown_background</item>
-       <item>@drawable/spinner_dropdown_background_down</item>
-       <item>@drawable/spinner_dropdown_background_up</item>
        <item>@drawable/spinner_focused_holo_dark</item>
        <item>@drawable/spinner_focused_holo_light</item>
        <item>@drawable/spinner_pressed_holo_dark</item>
@@ -337,7 +237,6 @@
        <item>@drawable/dialog_middle_holo_light</item>
        <item>@drawable/dialog_top_holo_dark</item>
        <item>@drawable/dialog_top_holo_light</item>
-       <item>@drawable/ic_dialog_alert</item>
        <item>@drawable/ic_dialog_alert_holo_dark</item>
        <item>@drawable/ic_dialog_alert_holo_light</item>
        <item>@drawable/list_divider_holo_dark</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 545a555..16b7ff3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1830,12 +1830,12 @@
         <!-- Defines whether the vertical scrollbar track should always be drawn. -->
         <attr name="scrollbarAlwaysDrawVerticalTrack" format="boolean" />
 
-        <!-- {@deprecated This attribute is deprecated and will be ignored as of
-             API level 14 (<code>android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH</code>).
+        <!-- This attribute is deprecated and will be ignored as of
+             API level 14 ({@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}).
              Using fading edges may introduce noticeable performance
              degradations and should be used only when required by the application's
              visual design. To request fading edges with API level 14 and above,
-             use the <code>requiresFadingEdge</code> attribute instead.} -->
+             use the <code>android:requiresFadingEdge</code> attribute instead. -->
         <attr name="fadingEdge">
             <!-- No edge is faded. -->
             <flag name="none" value="0x00000000" />
@@ -2061,7 +2061,7 @@
         </attr>
         <!-- Direction of the text. A heuristic is used to determine the resolved text direction
              of paragraphs. -->
-        <attr name="textDirection" format="integer">
+         <attr name="textDirection" format="integer">
             <!-- Default -->
             <enum name="inherit" value="0" />
             <!-- Default for the root view. The first strong directional character determines the
@@ -2072,16 +2072,12 @@
                  it is LTR if it contains any strong LTR characters.  If there are neither, the
                  paragraph direction is the view’s resolved layout direction. -->
             <enum name="anyRtl" value="2" />
-            <!-- The paragraph direction is the same as the one held by a 60% majority of the
-                 characters. If there is no majority then the paragraph direction is the resolved
-                 layout direction of the View. -->
-            <enum name="charCount" value="3" />
             <!-- The paragraph direction is left to right. -->
-            <enum name="ltr" value="4" />
+            <enum name="ltr" value="3" />
             <!-- The paragraph direction is right to left. -->
-            <enum name="rtl" value="5" />
+            <enum name="rtl" value="4" />
             <!-- The paragraph direction is coming from the system Locale. -->
-            <enum name="locale" value="6" />
+            <enum name="locale" value="5" />
         </attr>
     </declare-styleable>
 
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dbd49fb..92c59ab 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1235,6 +1235,10 @@
              when the user remove a task rooted in an activity owned by
              the application.  The default is false. -->
         <attr name="stopWithTask" format="boolean" />
+        <!-- If set to true, this service will run under a special process
+             that is isolated from the rest of the system.  The only communication
+             with it is through the Service API (binding and starting). -->
+        <attr name="isolatedProcess" format="boolean" />
     </declare-styleable>
     
     <!-- The <code>receiver</code> tag declares an
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bc132eb..3a7225e 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -61,6 +61,25 @@
          As of Honeycomb, blurring is not supported anymore. -->
     <bool name="config_sf_slowBlur">true</bool>
 
+    <!-- Flag indicating that the media framework should allow changing
+         master volume stream and nothing else . -->
+    <bool name="config_useMasterVolume">false</bool>
+
+    <!-- Array of integer pairs controlling the rate at which the master volume changes
+         in response to volume up and down key events.
+         The first integer of each pair is compared against the current master volume
+         (in range 0 to 100).
+         The last pair with first integer <= the current volume is chosen,
+         and the second integer of the pair indicates the amount to increase the master volume
+         when volume up is pressed. -->
+    <integer-array name="config_masterVolumeRamp">
+        <item>0</item>  <item>5</item>  <!-- default: always increase volume by 5% -->
+    </integer-array>
+
+    <!-- Flag indicating whether the AUDIO_BECOMING_NOISY notification should
+         be sent during an change to the audio output device. -->
+    <bool name="config_sendAudioBecomingNoisy">true</bool>
+
     <!-- The duration (in milliseconds) of a short animation. -->
     <integer name="config_shortAnimTime">200</integer>
 
@@ -361,7 +380,13 @@
          with the modem or some other restricted hardware, add "/dev/bus/usb/001/"
          to this list.  If this is empty, no parts of the host USB bus will be excluded.
     -->
-    <string-array name="config_usbHostBlacklist">
+    <string-array name="config_usbHostBlacklist" translatable="false">
+    </string-array>
+
+    <!-- List of paths to serial ports that are available to the serial manager.
+         for example, /dev/ttyUSB0
+    -->
+    <string-array translatable="false" name="config_serialPorts">
     </string-array>
 
     <!-- Vibrator pattern for feedback about a long screen/key press -->
@@ -533,13 +558,16 @@
 
     <!-- Component name of the default wallpaper. This will be ImageWallpaper if not
          specified -->
-    <string name="default_wallpaper_component">@null</string>
+    <string name="default_wallpaper_component" translatable="false">@null</string>
+
+    <!-- True if WallpaperService is enabled -->
+    <bool name="config_enableWallpaperService">true</bool>
 
     <!-- Component name of the service providing network location support. -->
-    <string name="config_networkLocationProvider">@null</string>
+    <string name="config_networkLocationProvider" translatable="false">@null</string>
 
     <!-- Component name of the service providing geocoder API support. -->
-    <string name="config_geocodeProvider">@null</string>
+    <string name="config_geocodeProvider" translatable="false">@null</string>
 
     <!-- Boolean indicating if current platform supports bluetooth SCO for off call
     use cases -->
@@ -563,7 +591,7 @@
     <integer name="config_datause_throttle_kbitsps">300</integer>
 
     <!-- The default iface on which to monitor data use -->
-    <string name="config_datause_iface">rmnet0</string>
+    <string name="config_datause_iface" translatable="false">rmnet0</string>
 
     <!-- The default reduced-datarate notification mask -->
     <!-- 2 means give warning -->
@@ -593,11 +621,11 @@
     <bool name="config_sms_capable">true</bool>
 
     <!-- IP address of the dns server to use if nobody else suggests one -->
-    <string name="config_default_dns_server">8.8.8.8</string>
+    <string name="config_default_dns_server" translatable="false">8.8.8.8</string>
 
     <!-- The default character set for GsmAlphabet -->
     <!-- Empty string means MBCS is not considered -->
-    <string name="gsm_alphabet_default_charset"></string>
+    <string name="gsm_alphabet_default_charset" translatable="false"></string>
 
     <!-- Enables SIP on WIFI only -->
     <bool name="config_sip_wifi_only">false</bool>
@@ -632,7 +660,7 @@
          OMA-TS-UAProf-V2_0-20060206-A Section 8.1.1.1. If the URL contains a '%s'
          format string then that substring will be replaced with the value of
          Build.MODEL. The format string shall not be escaped. -->
-    <string name="config_useragentprofile_url"></string>
+    <string name="config_useragentprofile_url" translatable="false"></string>
 
     <!-- When a database query is executed, the results retuned are paginated
          in pages of size (in KB) indicated by this value -->
@@ -643,7 +671,7 @@
     <bool name="config_showMenuShortcutsWhenKeyboardPresent">false</bool>
 
     <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
-    <string-array name="config_twoDigitNumberPattern">
+    <string-array name="config_twoDigitNumberPattern" translatable="false">
     </string-array>
 
     <!-- The VoiceMail default value is displayed to my own number if it is true -->
@@ -743,21 +771,27 @@
     <!-- Set and Unsets WiMAX -->
     <bool name="config_wimaxEnabled">false</bool>
     <!-- Location of the wimax framwork jar location -->
-    <string name="config_wimaxServiceJarLocation"></string>
+    <string name="config_wimaxServiceJarLocation" translatable="false"></string>
     <!-- Location of the wimax native library locaiton -->
-    <string name="config_wimaxNativeLibLocation"></string>
+    <string name="config_wimaxNativeLibLocation" translatable="false"></string>
     <!-- Name of the wimax manager class -->
-    <string name="config_wimaxManagerClassname"></string>
+    <string name="config_wimaxManagerClassname" translatable="false"></string>
     <!-- Name of the wimax service class -->
-    <string name="config_wimaxServiceClassname"></string>
+    <string name="config_wimaxServiceClassname" translatable="false"></string>
     <!-- Name of the wimax state tracker clas -->
-    <string name="config_wimaxStateTrackerClassname"></string>
+    <string name="config_wimaxStateTrackerClassname" translatable="false"></string>
 
     <!-- Name of screensaver components to look for if none has been chosen by the user -->
-    <string name="config_defaultDreamComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+    <string name="config_defaultDreamComponent" translatable="false">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
 
     <!-- Base "touch slop" value used by ViewConfiguration as a
          movement threshold where scrolling should begin. -->
     <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
 
+    <!-- Array of OEM specific USB mode override config.
+         OEM can override a certain USB mode depending on ro.bootmode.
+         Specify an array of below items to set override rule.
+         [bootmode]:[original USB mode]:[USB mode used]-->
+    <integer-array translatable="false" name="config_oemUsbModeOverride">
+    </integer-array>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4d97ad2..4e55b4f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -23,6 +23,1522 @@
        SDK.  Instead, put them here. -->
   <private-symbols package="com.android.internal" />
 
+  <!-- Private symbols that we need to reference from framework code.  See
+       frameworks/base/core/res/MakeJavaSymbols.sed for how to easily generate
+       this.
+  -->
+  <java-symbol type="id" name="account_name" />
+  <java-symbol type="id" name="account_row_checkmark" />
+  <java-symbol type="id" name="account_row_icon" />
+  <java-symbol type="id" name="account_row_text" />
+  <java-symbol type="id" name="account_type" />
+  <java-symbol type="id" name="action_bar" />
+  <java-symbol type="id" name="action_bar_container" />
+  <java-symbol type="id" name="action_bar_title" />
+  <java-symbol type="id" name="action_bar_subtitle" />
+  <java-symbol type="id" name="action_context_bar" />
+  <java-symbol type="id" name="action_menu_presenter" />
+  <java-symbol type="id" name="action_mode_close_button" />
+  <java-symbol type="id" name="activity_chooser_view_content" />
+  <java-symbol type="id" name="addAccount" />
+  <java-symbol type="id" name="albumart" />
+  <java-symbol type="id" name="alertTitle" />
+  <java-symbol type="id" name="allow_button" />
+  <java-symbol type="id" name="alwaysUse" />
+  <java-symbol type="id" name="amPm" />
+  <java-symbol type="id" name="authtoken_type" />
+  <java-symbol type="id" name="back_button" />
+  <java-symbol type="id" name="btn_next" />
+  <java-symbol type="id" name="btn_play" />
+  <java-symbol type="id" name="btn_prev" />
+  <java-symbol type="id" name="button_bar" />
+  <java-symbol type="id" name="buttonPanel" />
+  <java-symbol type="id" name="by_common" />
+  <java-symbol type="id" name="by_org" />
+  <java-symbol type="id" name="by_org_unit" />
+  <java-symbol type="id" name="calendar_view" />
+  <java-symbol type="id" name="cancel" />
+  <java-symbol type="id" name="characterPicker" />
+  <java-symbol type="id" name="clearDefaultHint" />
+  <java-symbol type="id" name="contentPanel" />
+  <java-symbol type="id" name="customPanel" />
+  <java-symbol type="id" name="dangerous_perms_list" />
+  <java-symbol type="id" name="datePicker" />
+  <java-symbol type="id" name="day" />
+  <java-symbol type="id" name="day_names" />
+  <java-symbol type="id" name="decrement" />
+  <java-symbol type="id" name="default_activity_button" />
+  <java-symbol type="id" name="deny_button" />
+  <java-symbol type="id" name="description" />
+  <java-symbol type="id" name="divider" />
+  <java-symbol type="id" name="edit_query" />
+  <java-symbol type="id" name="edittext_container" />
+  <java-symbol type="id" name="enter_pin_section" />
+  <java-symbol type="id" name="expand_activities_button" />
+  <java-symbol type="id" name="expand_button" />
+  <java-symbol type="id" name="expand_button_divider" />
+  <java-symbol type="id" name="expires_on" />
+  <java-symbol type="id" name="find_next" />
+  <java-symbol type="id" name="find_prev" />
+  <java-symbol type="id" name="ffwd" />
+  <java-symbol type="id" name="fillInIntent" />
+  <java-symbol type="id" name="find" />
+  <java-symbol type="id" name="fullscreenArea" />
+  <java-symbol type="id" name="headers" />
+  <java-symbol type="id" name="hour" />
+  <java-symbol type="id" name="icon" />
+  <java-symbol type="id" name="image" />
+  <java-symbol type="id" name="imageButton" />
+  <java-symbol type="id" name="increment" />
+  <java-symbol type="id" name="internalEmpty" />
+  <java-symbol type="id" name="info" />
+  <java-symbol type="id" name="inputExtractAccessories" />
+  <java-symbol type="id" name="inputExtractAction" />
+  <java-symbol type="id" name="inputExtractEditButton" />
+  <java-symbol type="id" name="issued_on" />
+  <java-symbol type="id" name="left_icon" />
+  <java-symbol type="id" name="leftSpacer" />
+  <java-symbol type="id" name="line3" />
+  <java-symbol type="id" name="list_footer" />
+  <java-symbol type="id" name="list_item" />
+  <java-symbol type="id" name="listContainer" />
+  <java-symbol type="id" name="locale" />
+  <java-symbol type="id" name="matches" />
+  <java-symbol type="id" name="mediacontroller_progress" />
+  <java-symbol type="id" name="minute" />
+  <java-symbol type="id" name="mode_normal" />
+  <java-symbol type="id" name="month" />
+  <java-symbol type="id" name="month_name" />
+  <java-symbol type="id" name="name" />
+  <java-symbol type="id" name="next" />
+  <java-symbol type="id" name="next_button" />
+  <java-symbol type="id" name="new_app_action" />
+  <java-symbol type="id" name="new_app_description" />
+  <java-symbol type="id" name="new_app_icon" />
+  <java-symbol type="id" name="no_permissions" />
+  <java-symbol type="id" name="non_dangerous_perms_list" />
+  <java-symbol type="id" name="numberpicker_input" />
+  <java-symbol type="id" name="old_app_action" />
+  <java-symbol type="id" name="old_app_description" />
+  <java-symbol type="id" name="old_app_icon" />
+  <java-symbol type="id" name="package_label" />
+  <java-symbol type="id" name="packages_list" />
+  <java-symbol type="id" name="pause" />
+  <java-symbol type="id" name="perm_icon" />
+  <java-symbol type="id" name="permission_group" />
+  <java-symbol type="id" name="permission_list" />
+  <java-symbol type="id" name="pickers" />
+  <java-symbol type="id" name="prefs" />
+  <java-symbol type="id" name="prefs_frame" />
+  <java-symbol type="id" name="prev" />
+  <java-symbol type="id" name="progress" />
+  <java-symbol type="id" name="progress_circular" />
+  <java-symbol type="id" name="progress_horizontal" />
+  <java-symbol type="id" name="progress_number" />
+  <java-symbol type="id" name="progress_percent" />
+  <java-symbol type="id" name="progressContainer" />
+  <java-symbol type="id" name="rew" />
+  <java-symbol type="id" name="rightSpacer" />
+  <java-symbol type="id" name="rowTypeId" />
+  <java-symbol type="id" name="scrollView" />
+  <java-symbol type="id" name="search_app_icon" />
+  <java-symbol type="id" name="search_badge" />
+  <java-symbol type="id" name="search_bar" />
+  <java-symbol type="id" name="search_button" />
+  <java-symbol type="id" name="search_close_btn" />
+  <java-symbol type="id" name="search_edit_frame" />
+  <java-symbol type="id" name="search_go_btn" />
+  <java-symbol type="id" name="search_mag_icon" />
+  <java-symbol type="id" name="search_plate" />
+  <java-symbol type="id" name="search_src_text" />
+  <java-symbol type="id" name="search_view" />
+  <java-symbol type="id" name="search_voice_btn" />
+  <java-symbol type="id" name="select_all" />
+  <java-symbol type="id" name="serial_number" />
+  <java-symbol type="id" name="seekbar" />
+  <java-symbol type="id" name="sha1_fingerprint" />
+  <java-symbol type="id" name="sha256_fingerprint" />
+  <java-symbol type="id" name="share" />
+  <java-symbol type="id" name="shortcut" />
+  <java-symbol type="id" name="show_more" />
+  <java-symbol type="id" name="show_more_icon" />
+  <java-symbol type="id" name="show_more_text" />
+  <java-symbol type="id" name="skip_button" />
+  <java-symbol type="id" name="slider_group" />
+  <java-symbol type="id" name="split_action_bar" />
+  <java-symbol type="id" name="stream_icon" />
+  <java-symbol type="id" name="submit_area" />
+  <java-symbol type="id" name="switch_new" />
+  <java-symbol type="id" name="switch_old" />
+  <java-symbol type="id" name="switchWidget" />
+  <java-symbol type="id" name="text" />
+  <java-symbol type="id" name="textButton" />
+  <java-symbol type="id" name="time" />
+  <java-symbol type="id" name="time_current" />
+  <java-symbol type="id" name="timeDisplayBackground" />
+  <java-symbol type="id" name="timeDisplayForeground" />
+  <java-symbol type="id" name="titleDivider" />
+  <java-symbol type="id" name="titleDividerTop" />
+  <java-symbol type="id" name="timePicker" />
+  <java-symbol type="id" name="title_template" />
+  <java-symbol type="id" name="to_common" />
+  <java-symbol type="id" name="to_org" />
+  <java-symbol type="id" name="to_org_unit" />
+  <java-symbol type="id" name="topPanel" />
+  <java-symbol type="id" name="up" />
+  <java-symbol type="id" name="value" />
+  <java-symbol type="id" name="visible_panel" />
+  <java-symbol type="id" name="websearch" />
+  <java-symbol type="id" name="wifi_p2p_wps_pin" />
+  <java-symbol type="id" name="year" />
+  <java-symbol type="id" name="zoomControls" />
+  <java-symbol type="id" name="zoomIn" />
+  <java-symbol type="id" name="zoomMagnify" />
+  <java-symbol type="id" name="zoomOut" />
+
+  <java-symbol type="attr" name="actionModeShareDrawable" />
+  <java-symbol type="attr" name="alertDialogCenterButtons" />
+  <java-symbol type="attr" name="gestureOverlayViewStyle" />
+  <java-symbol type="attr" name="keyboardViewStyle" />
+  <java-symbol type="attr" name="numberPickerStyle" />
+  <java-symbol type="attr" name="pointerStyle" />
+  <java-symbol type="attr" name="preferenceFrameLayoutStyle" />
+  <java-symbol type="attr" name="searchDialogTheme" />
+  <java-symbol type="attr" name="searchViewSearchIcon" />
+  <java-symbol type="attr" name="stackViewStyle" />
+  <java-symbol type="attr" name="switchStyle" />
+  <java-symbol type="attr" name="textAppearanceAutoCorrectionSuggestion" />
+  <java-symbol type="attr" name="textAppearanceEasyCorrectSuggestion" />
+  <java-symbol type="attr" name="textAppearanceMisspelledSuggestion" />
+  <java-symbol type="attr" name="textColorSearchUrl" />
+  <java-symbol type="attr" name="timePickerStyle" />
+
+  <java-symbol type="bool" name="action_bar_embed_tabs" />
+  <java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
+  <java-symbol type="bool" name="config_allowActionMenuItemTextWithIcon" />
+  <java-symbol type="bool" name="config_bluetooth_adapter_quick_switch" />
+  <java-symbol type="bool" name="config_bluetooth_sco_off_call" />
+  <java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
+  <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
+  <java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
+  <java-symbol type="bool" name="config_enable_puk_unlock_screen" />
+  <java-symbol type="bool" name="config_mms_content_disposition_support" />
+  <java-symbol type="bool" name="config_showMenuShortcutsWhenKeyboardPresent" />
+  <java-symbol type="bool" name="config_sip_wifi_only" />
+  <java-symbol type="bool" name="config_sms_capable" />
+  <java-symbol type="bool" name="config_sms_utf8_support" />
+  <java-symbol type="bool" name="config_swipeDisambiguation" />
+  <java-symbol type="bool" name="config_telephony_use_own_number_for_voicemail" />
+  <java-symbol type="bool" name="config_ui_enableFadingMarquee" />
+  <java-symbol type="bool" name="config_use_strict_phone_number_comparation" />
+  <java-symbol type="bool" name="config_voice_capable" />
+  <java-symbol type="bool" name="preferences_prefer_dual_pane" />
+  <java-symbol type="bool" name="skip_restoring_network_selection" />
+  <java-symbol type="bool" name="split_action_bar_is_narrow" />
+  <java-symbol type="bool" name="config_useMasterVolume" />
+  <java-symbol type="bool" name="config_enableWallpaperService" />
+  <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
+
+  <java-symbol type="integer" name="config_cursorWindowSize" />
+  <java-symbol type="integer" name="config_longPressOnPowerBehavior" />
+  <java-symbol type="integer" name="config_max_pan_devices" />
+  <java-symbol type="integer" name="config_ntpTimeout" />
+  <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
+  <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
+  <java-symbol type="integer" name="db_connection_pool_size" />
+  <java-symbol type="integer" name="max_action_buttons" />
+
+  <java-symbol type="color" name="tab_indicator_text_v4" />
+
+  <java-symbol type="dimen" name="config_prefDialogWidth" />
+  <java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
+  <java-symbol type="dimen" name="default_app_widget_padding_bottom" />
+  <java-symbol type="dimen" name="default_app_widget_padding_left" />
+  <java-symbol type="dimen" name="default_app_widget_padding_right" />
+  <java-symbol type="dimen" name="default_app_widget_padding_top" />
+  <java-symbol type="dimen" name="default_gap" />
+  <java-symbol type="dimen" name="dropdownitem_icon_width" />
+  <java-symbol type="dimen" name="dropdownitem_text_padding_left" />
+  <java-symbol type="dimen" name="fastscroll_overlay_size" />
+  <java-symbol type="dimen" name="fastscroll_thumb_height" />
+  <java-symbol type="dimen" name="fastscroll_thumb_width" />
+  <java-symbol type="dimen" name="fastscroll_thumb_width" />
+  <java-symbol type="dimen" name="password_keyboard_spacebar_vertical_correction" />
+  <java-symbol type="dimen" name="search_view_preferred_width" />
+  <java-symbol type="dimen" name="textview_error_popup_default_width" />
+  <java-symbol type="dimen" name="toast_y_offset" />
+  <java-symbol type="dimen" name="volume_panel_top" />
+
+  <java-symbol type="string" name="addToDictionary" />
+  <java-symbol type="string" name="action_bar_home_description" />
+  <java-symbol type="string" name="action_bar_up_description" />
+  <java-symbol type="string" name="delete" />
+  <java-symbol type="string" name="deleteText" />
+  <java-symbol type="string" name="ellipsis_two_dots" />
+  <java-symbol type="string" name="ellipsis" />
+  <java-symbol type="string" name="grant_permissions_header_text" />
+  <java-symbol type="string" name="list_delimeter" />
+  <java-symbol type="string" name="menu_delete_shortcut_label" />
+  <java-symbol type="string" name="menu_enter_shortcut_label" />
+  <java-symbol type="string" name="menu_space_shortcut_label" />
+  <java-symbol type="string" name="notification_title" />
+  <java-symbol type="string" name="permission_request_notification_with_subtitle" />
+  <java-symbol type="string" name="prepend_shortcut_label" />
+  <java-symbol type="string" name="replace" />
+  <java-symbol type="string" name="textSelectionCABTitle" />
+  <java-symbol type="string" name="BaMmi" />
+  <java-symbol type="string" name="CLIRDefaultOffNextCallOff" />
+  <java-symbol type="string" name="CLIRDefaultOffNextCallOn" />
+  <java-symbol type="string" name="CLIRDefaultOnNextCallOff" />
+  <java-symbol type="string" name="CLIRDefaultOnNextCallOn" />
+  <java-symbol type="string" name="CLIRPermanent" />
+  <java-symbol type="string" name="CfMmi" />
+  <java-symbol type="string" name="ClipMmi" />
+  <java-symbol type="string" name="ClirMmi" />
+  <java-symbol type="string" name="CwMmi" />
+  <java-symbol type="string" name="Midnight" />
+  <java-symbol type="string" name="Noon" />
+  <java-symbol type="string" name="PinMmi" />
+  <java-symbol type="string" name="PwdMmi" />
+  <java-symbol type="string" name="RestrictedChangedTitle" />
+  <java-symbol type="string" name="RestrictedOnAllVoice" />
+  <java-symbol type="string" name="RestrictedOnData" />
+  <java-symbol type="string" name="RestrictedOnEmergency" />
+  <java-symbol type="string" name="RestrictedOnNormal" />
+  <java-symbol type="string" name="SetupCallDefault" />
+  <java-symbol type="string" name="abbrev_month" />
+  <java-symbol type="string" name="abbrev_month_day" />
+  <java-symbol type="string" name="abbrev_month_day_year" />
+  <java-symbol type="string" name="abbrev_month_year" />
+  <java-symbol type="string" name="accept" />
+  <java-symbol type="string" name="activity_chooser_view_see_all" />
+  <java-symbol type="string" name="activitychooserview_choose_application" />
+  <java-symbol type="string" name="alternate_eri_file" />
+  <java-symbol type="string" name="alwaysUse" />
+  <java-symbol type="string" name="am" />
+  <java-symbol type="string" name="autofill_address_line_1_label_re" />
+  <java-symbol type="string" name="autofill_address_line_1_re" />
+  <java-symbol type="string" name="autofill_address_line_2_re" />
+  <java-symbol type="string" name="autofill_address_line_3_re" />
+  <java-symbol type="string" name="autofill_address_name_separator" />
+  <java-symbol type="string" name="autofill_address_summary_format" />
+  <java-symbol type="string" name="autofill_address_summary_name_format" />
+  <java-symbol type="string" name="autofill_address_summary_separator" />
+  <java-symbol type="string" name="autofill_address_type_same_as_re" />
+  <java-symbol type="string" name="autofill_address_type_use_my_re" />
+  <java-symbol type="string" name="autofill_area" />
+  <java-symbol type="string" name="autofill_area_code_notext_re" />
+  <java-symbol type="string" name="autofill_area_code_re" />
+  <java-symbol type="string" name="autofill_attention_ignored_re" />
+  <java-symbol type="string" name="autofill_billing_designator_re" />
+  <java-symbol type="string" name="autofill_card_cvc_re" />
+  <java-symbol type="string" name="autofill_card_ignored_re" />
+  <java-symbol type="string" name="autofill_card_number_re" />
+  <java-symbol type="string" name="autofill_city_re" />
+  <java-symbol type="string" name="autofill_company_re" />
+  <java-symbol type="string" name="autofill_country_code_re" />
+  <java-symbol type="string" name="autofill_country_re" />
+  <java-symbol type="string" name="autofill_county" />
+  <java-symbol type="string" name="autofill_department" />
+  <java-symbol type="string" name="autofill_district" />
+  <java-symbol type="string" name="autofill_email_re" />
+  <java-symbol type="string" name="autofill_emirate" />
+  <java-symbol type="string" name="autofill_expiration_date_re" />
+  <java-symbol type="string" name="autofill_expiration_month_re" />
+  <java-symbol type="string" name="autofill_fax_re" />
+  <java-symbol type="string" name="autofill_first_name_re" />
+  <java-symbol type="string" name="autofill_island" />
+  <java-symbol type="string" name="autofill_last_name_re" />
+  <java-symbol type="string" name="autofill_middle_initial_re" />
+  <java-symbol type="string" name="autofill_middle_name_re" />
+  <java-symbol type="string" name="autofill_name_on_card_contextual_re" />
+  <java-symbol type="string" name="autofill_name_on_card_re" />
+  <java-symbol type="string" name="autofill_name_re" />
+  <java-symbol type="string" name="autofill_name_specific_re" />
+  <java-symbol type="string" name="autofill_parish" />
+  <java-symbol type="string" name="autofill_phone_extension_re" />
+  <java-symbol type="string" name="autofill_phone_prefix_re" />
+  <java-symbol type="string" name="autofill_phone_prefix_separator_re" />
+  <java-symbol type="string" name="autofill_phone_re" />
+  <java-symbol type="string" name="autofill_phone_suffix_re" />
+  <java-symbol type="string" name="autofill_phone_suffix_separator_re" />
+  <java-symbol type="string" name="autofill_postal_code" />
+  <java-symbol type="string" name="autofill_prefecture" />
+  <java-symbol type="string" name="autofill_province" />
+  <java-symbol type="string" name="autofill_region_ignored_re" />
+  <java-symbol type="string" name="autofill_shipping_designator_re" />
+  <java-symbol type="string" name="autofill_state" />
+  <java-symbol type="string" name="autofill_state_re" />
+  <java-symbol type="string" name="autofill_this_form" />
+  <java-symbol type="string" name="autofill_username_re" />
+  <java-symbol type="string" name="autofill_zip_4_re" />
+  <java-symbol type="string" name="autofill_zip_code" />
+  <java-symbol type="string" name="autofill_zip_code_re" />
+  <java-symbol type="string" name="badPin" />
+  <java-symbol type="string" name="badPuk" />
+  <java-symbol type="string" name="byteShort" />
+  <java-symbol type="string" name="cfTemplateForwarded" />
+  <java-symbol type="string" name="cfTemplateForwardedTime" />
+  <java-symbol type="string" name="cfTemplateNotForwarded" />
+  <java-symbol type="string" name="cfTemplateRegistered" />
+  <java-symbol type="string" name="cfTemplateRegisteredTime" />
+  <java-symbol type="string" name="checkbox_checked" />
+  <java-symbol type="string" name="checkbox_not_checked" />
+  <java-symbol type="string" name="chooseActivity" />
+  <java-symbol type="string" name="config_default_dns_server" />
+  <java-symbol type="string" name="config_ethernet_iface_regex" />
+  <java-symbol type="string" name="config_ntpServer" />
+  <java-symbol type="string" name="config_tether_apndata" />
+  <java-symbol type="string" name="config_useragentprofile_url" />
+  <java-symbol type="string" name="config_wifi_p2p_device_type" />
+  <java-symbol type="string" name="contentServiceSync" />
+  <java-symbol type="string" name="contentServiceSyncNotificationTitle" />
+  <java-symbol type="string" name="contentServiceTooManyDeletesNotificationDesc" />
+  <java-symbol type="string" name="date1_date2" />
+  <java-symbol type="string" name="date1_time1_date2_time2" />
+  <java-symbol type="string" name="date_and_time" />
+  <java-symbol type="string" name="date_picker_decrement_day_button" />
+  <java-symbol type="string" name="date_picker_decrement_month_button" />
+  <java-symbol type="string" name="date_picker_decrement_year_button" />
+  <java-symbol type="string" name="date_picker_dialog_title" />
+  <java-symbol type="string" name="date_picker_increment_day_button" />
+  <java-symbol type="string" name="date_picker_increment_month_button" />
+  <java-symbol type="string" name="date_picker_increment_year_button" />
+  <java-symbol type="string" name="date_time" />
+  <java-symbol type="string" name="date_time_set" />
+  <java-symbol type="string" name="day_of_week_long_friday" />
+  <java-symbol type="string" name="day_of_week_long_monday" />
+  <java-symbol type="string" name="day_of_week_long_saturday" />
+  <java-symbol type="string" name="day_of_week_long_sunday" />
+  <java-symbol type="string" name="day_of_week_long_thursday" />
+  <java-symbol type="string" name="day_of_week_long_tuesday" />
+  <java-symbol type="string" name="day_of_week_long_wednesday" />
+  <java-symbol type="string" name="day_of_week_medium_friday" />
+  <java-symbol type="string" name="day_of_week_medium_monday" />
+  <java-symbol type="string" name="day_of_week_medium_saturday" />
+  <java-symbol type="string" name="day_of_week_medium_sunday" />
+  <java-symbol type="string" name="day_of_week_medium_thursday" />
+  <java-symbol type="string" name="day_of_week_medium_tuesday" />
+  <java-symbol type="string" name="day_of_week_medium_wednesday" />
+  <java-symbol type="string" name="day_of_week_short_friday" />
+  <java-symbol type="string" name="day_of_week_short_monday" />
+  <java-symbol type="string" name="day_of_week_short_saturday" />
+  <java-symbol type="string" name="day_of_week_short_sunday" />
+  <java-symbol type="string" name="day_of_week_short_thursday" />
+  <java-symbol type="string" name="day_of_week_short_tuesday" />
+  <java-symbol type="string" name="day_of_week_short_wednesday" />
+  <java-symbol type="string" name="day_of_week_shortest_friday" />
+  <java-symbol type="string" name="day_of_week_shortest_monday" />
+  <java-symbol type="string" name="day_of_week_shortest_saturday" />
+  <java-symbol type="string" name="day_of_week_shortest_sunday" />
+  <java-symbol type="string" name="day_of_week_shortest_thursday" />
+  <java-symbol type="string" name="day_of_week_shortest_tuesday" />
+  <java-symbol type="string" name="day_of_week_shortest_wednesday" />
+  <java-symbol type="string" name="decline" />
+  <java-symbol type="string" name="default_permission_group" />
+  <java-symbol type="string" name="default_text_encoding" />
+  <java-symbol type="string" name="description_target_unlock_tablet" />
+  <java-symbol type="string" name="double_tap_toast" />
+  <java-symbol type="string" name="elapsed_time_short_format_h_mm_ss" />
+  <java-symbol type="string" name="elapsed_time_short_format_mm_ss" />
+  <java-symbol type="string" name="emailTypeCustom" />
+  <java-symbol type="string" name="emailTypeHome" />
+  <java-symbol type="string" name="emailTypeMobile" />
+  <java-symbol type="string" name="emailTypeOther" />
+  <java-symbol type="string" name="emailTypeWork" />
+  <java-symbol type="string" name="emergency_call_dialog_number_for_display" />
+  <java-symbol type="string" name="emergency_calls_only" />
+  <java-symbol type="string" name="eventTypeAnniversary" />
+  <java-symbol type="string" name="eventTypeBirthday" />
+  <java-symbol type="string" name="eventTypeCustom" />
+  <java-symbol type="string" name="eventTypeOther" />
+  <java-symbol type="string" name="extmedia_format_button_format" />
+  <java-symbol type="string" name="extmedia_format_message" />
+  <java-symbol type="string" name="extmedia_format_title" />
+  <java-symbol type="string" name="fileSizeSuffix" />
+  <java-symbol type="string" name="force_close" />
+  <java-symbol type="string" name="format_error" />
+  <java-symbol type="string" name="gadget_host_error_inflating" />
+  <java-symbol type="string" name="gigabyteShort" />
+  <java-symbol type="string" name="gpsNotifMessage" />
+  <java-symbol type="string" name="gpsNotifTicker" />
+  <java-symbol type="string" name="gpsNotifTitle" />
+  <java-symbol type="string" name="gpsVerifNo" />
+  <java-symbol type="string" name="gpsVerifYes" />
+  <java-symbol type="string" name="gsm_alphabet_default_charset" />
+  <java-symbol type="string" name="hour_ampm" />
+  <java-symbol type="string" name="hour_cap_ampm" />
+  <java-symbol type="string" name="hour_minute_24" />
+  <java-symbol type="string" name="hour_minute_ampm" />
+  <java-symbol type="string" name="hour_minute_cap_ampm" />
+  <java-symbol type="string" name="httpError" />
+  <java-symbol type="string" name="httpErrorAuth" />
+  <java-symbol type="string" name="httpErrorConnect" />
+  <java-symbol type="string" name="httpErrorFailedSslHandshake" />
+  <java-symbol type="string" name="httpErrorFile" />
+  <java-symbol type="string" name="httpErrorFileNotFound" />
+  <java-symbol type="string" name="httpErrorIO" />
+  <java-symbol type="string" name="httpErrorLookup" />
+  <java-symbol type="string" name="httpErrorOk" />
+  <java-symbol type="string" name="httpErrorProxyAuth" />
+  <java-symbol type="string" name="httpErrorRedirectLoop" />
+  <java-symbol type="string" name="httpErrorTimeout" />
+  <java-symbol type="string" name="httpErrorTooManyRequests" />
+  <java-symbol type="string" name="httpErrorUnsupportedAuthScheme" />
+  <java-symbol type="string" name="imProtocolAim" />
+  <java-symbol type="string" name="imProtocolCustom" />
+  <java-symbol type="string" name="imProtocolGoogleTalk" />
+  <java-symbol type="string" name="imProtocolIcq" />
+  <java-symbol type="string" name="imProtocolJabber" />
+  <java-symbol type="string" name="imProtocolMsn" />
+  <java-symbol type="string" name="imProtocolNetMeeting" />
+  <java-symbol type="string" name="imProtocolQq" />
+  <java-symbol type="string" name="imProtocolSkype" />
+  <java-symbol type="string" name="imProtocolYahoo" />
+  <java-symbol type="string" name="imTypeCustom" />
+  <java-symbol type="string" name="imTypeHome" />
+  <java-symbol type="string" name="imTypeOther" />
+  <java-symbol type="string" name="imTypeWork" />
+  <java-symbol type="string" name="ime_action_default" />
+  <java-symbol type="string" name="ime_action_done" />
+  <java-symbol type="string" name="ime_action_go" />
+  <java-symbol type="string" name="ime_action_next" />
+  <java-symbol type="string" name="ime_action_previous" />
+  <java-symbol type="string" name="ime_action_search" />
+  <java-symbol type="string" name="ime_action_send" />
+  <java-symbol type="string" name="invalidPin" />
+  <java-symbol type="string" name="js_dialog_before_unload" />
+  <java-symbol type="string" name="js_dialog_title" />
+  <java-symbol type="string" name="js_dialog_title_default" />
+  <java-symbol type="string" name="keyboard_headset_required_to_hear_password" />
+  <java-symbol type="string" name="keyboard_password_character_no_headset" />
+  <java-symbol type="string" name="keyboardview_keycode_alt" />
+  <java-symbol type="string" name="keyboardview_keycode_cancel" />
+  <java-symbol type="string" name="keyboardview_keycode_delete" />
+  <java-symbol type="string" name="keyboardview_keycode_done" />
+  <java-symbol type="string" name="keyboardview_keycode_enter" />
+  <java-symbol type="string" name="keyboardview_keycode_mode_change" />
+  <java-symbol type="string" name="keyboardview_keycode_shift" />
+  <java-symbol type="string" name="kilobyteShort" />
+  <java-symbol type="string" name="last_month" />
+  <java-symbol type="string" name="launchBrowserDefault" />
+  <java-symbol type="string" name="lockscreen_access_pattern_cell_added" />
+  <java-symbol type="string" name="lockscreen_access_pattern_cleared" />
+  <java-symbol type="string" name="lockscreen_access_pattern_detected" />
+  <java-symbol type="string" name="lockscreen_access_pattern_start" />
+  <java-symbol type="string" name="lockscreen_emergency_call" />
+  <java-symbol type="string" name="lockscreen_return_to_call" />
+  <java-symbol type="string" name="lockscreen_transport_pause_description" />
+  <java-symbol type="string" name="lockscreen_transport_play_description" />
+  <java-symbol type="string" name="lockscreen_transport_stop_description" />
+  <java-symbol type="string" name="low_memory" />
+  <java-symbol type="string" name="media_bad_removal" />
+  <java-symbol type="string" name="media_checking" />
+  <java-symbol type="string" name="media_removed" />
+  <java-symbol type="string" name="media_shared" />
+  <java-symbol type="string" name="media_unknown_state" />
+  <java-symbol type="string" name="megabyteShort" />
+  <java-symbol type="string" name="midnight" />
+  <java-symbol type="string" name="mismatchPin" />
+  <java-symbol type="string" name="mmiComplete" />
+  <java-symbol type="string" name="mmiError" />
+  <java-symbol type="string" name="mmiFdnError" />
+  <java-symbol type="string" name="month" />
+  <java-symbol type="string" name="month_day" />
+  <java-symbol type="string" name="month_day_year" />
+  <java-symbol type="string" name="month_long_april" />
+  <java-symbol type="string" name="month_long_august" />
+  <java-symbol type="string" name="month_long_december" />
+  <java-symbol type="string" name="month_long_february" />
+  <java-symbol type="string" name="month_long_january" />
+  <java-symbol type="string" name="month_long_july" />
+  <java-symbol type="string" name="month_long_june" />
+  <java-symbol type="string" name="month_long_march" />
+  <java-symbol type="string" name="month_long_may" />
+  <java-symbol type="string" name="month_long_november" />
+  <java-symbol type="string" name="month_long_october" />
+  <java-symbol type="string" name="month_long_september" />
+  <java-symbol type="string" name="month_long_standalone_april" />
+  <java-symbol type="string" name="month_long_standalone_august" />
+  <java-symbol type="string" name="month_long_standalone_december" />
+  <java-symbol type="string" name="month_long_standalone_february" />
+  <java-symbol type="string" name="month_long_standalone_january" />
+  <java-symbol type="string" name="month_long_standalone_july" />
+  <java-symbol type="string" name="month_long_standalone_june" />
+  <java-symbol type="string" name="month_long_standalone_march" />
+  <java-symbol type="string" name="month_long_standalone_may" />
+  <java-symbol type="string" name="month_long_standalone_november" />
+  <java-symbol type="string" name="month_long_standalone_october" />
+  <java-symbol type="string" name="month_long_standalone_september" />
+  <java-symbol type="string" name="month_medium_april" />
+  <java-symbol type="string" name="month_medium_august" />
+  <java-symbol type="string" name="month_medium_december" />
+  <java-symbol type="string" name="month_medium_february" />
+  <java-symbol type="string" name="month_medium_january" />
+  <java-symbol type="string" name="month_medium_july" />
+  <java-symbol type="string" name="month_medium_june" />
+  <java-symbol type="string" name="month_medium_march" />
+  <java-symbol type="string" name="month_medium_may" />
+  <java-symbol type="string" name="month_medium_november" />
+  <java-symbol type="string" name="month_medium_october" />
+  <java-symbol type="string" name="month_medium_september" />
+  <java-symbol type="string" name="month_shortest_april" />
+  <java-symbol type="string" name="month_shortest_august" />
+  <java-symbol type="string" name="month_shortest_december" />
+  <java-symbol type="string" name="month_shortest_february" />
+  <java-symbol type="string" name="month_shortest_january" />
+  <java-symbol type="string" name="month_shortest_july" />
+  <java-symbol type="string" name="month_shortest_june" />
+  <java-symbol type="string" name="month_shortest_march" />
+  <java-symbol type="string" name="month_shortest_may" />
+  <java-symbol type="string" name="month_shortest_november" />
+  <java-symbol type="string" name="month_shortest_october" />
+  <java-symbol type="string" name="month_shortest_september" />
+  <java-symbol type="string" name="month_year" />
+  <java-symbol type="string" name="more_item_label" />
+  <java-symbol type="string" name="needPuk" />
+  <java-symbol type="string" name="needPuk2" />
+  <java-symbol type="string" name="new_app_action" />
+  <java-symbol type="string" name="new_app_description" />
+  <java-symbol type="string" name="noApplications" />
+  <java-symbol type="string" name="no_file_chosen" />
+  <java-symbol type="string" name="no_matches" />
+  <java-symbol type="string" name="noon" />
+  <java-symbol type="string" name="number_picker_increment_scroll_action" />
+  <java-symbol type="string" name="number_picker_increment_scroll_mode" />
+  <java-symbol type="string" name="numeric_date" />
+  <java-symbol type="string" name="numeric_date_format" />
+  <java-symbol type="string" name="numeric_date_template" />
+  <java-symbol type="string" name="numeric_md1_md2" />
+  <java-symbol type="string" name="numeric_md1_time1_md2_time2" />
+  <java-symbol type="string" name="numeric_mdy1_mdy2" />
+  <java-symbol type="string" name="numeric_mdy1_time1_mdy2_time2" />
+  <java-symbol type="string" name="numeric_wday1_md1_time1_wday2_md2_time2" />
+  <java-symbol type="string" name="numeric_wday1_md1_wday2_md2" />
+  <java-symbol type="string" name="numeric_wday1_mdy1_time1_wday2_mdy2_time2" />
+  <java-symbol type="string" name="numeric_wday1_mdy1_wday2_mdy2" />
+  <java-symbol type="string" name="old_app_action" />
+  <java-symbol type="string" name="old_app_description" />
+  <java-symbol type="string" name="older" />
+  <java-symbol type="string" name="open_permission_deny" />
+  <java-symbol type="string" name="orgTypeCustom" />
+  <java-symbol type="string" name="orgTypeOther" />
+  <java-symbol type="string" name="orgTypeWork" />
+  <java-symbol type="string" name="passwordIncorrect" />
+  <java-symbol type="string" name="permissions_format" />
+  <java-symbol type="string" name="perms_hide" />
+  <java-symbol type="string" name="perms_show_all" />
+  <java-symbol type="string" name="petabyteShort" />
+  <java-symbol type="string" name="phoneTypeAssistant" />
+  <java-symbol type="string" name="phoneTypeCallback" />
+  <java-symbol type="string" name="phoneTypeCar" />
+  <java-symbol type="string" name="phoneTypeCompanyMain" />
+  <java-symbol type="string" name="phoneTypeCustom" />
+  <java-symbol type="string" name="phoneTypeFaxHome" />
+  <java-symbol type="string" name="phoneTypeFaxWork" />
+  <java-symbol type="string" name="phoneTypeHome" />
+  <java-symbol type="string" name="phoneTypeIsdn" />
+  <java-symbol type="string" name="phoneTypeMain" />
+  <java-symbol type="string" name="phoneTypeMms" />
+  <java-symbol type="string" name="phoneTypeMobile" />
+  <java-symbol type="string" name="phoneTypeOther" />
+  <java-symbol type="string" name="phoneTypeOtherFax" />
+  <java-symbol type="string" name="phoneTypePager" />
+  <java-symbol type="string" name="phoneTypeRadio" />
+  <java-symbol type="string" name="phoneTypeTelex" />
+  <java-symbol type="string" name="phoneTypeTtyTdd" />
+  <java-symbol type="string" name="phoneTypeWork" />
+  <java-symbol type="string" name="phoneTypeWorkMobile" />
+  <java-symbol type="string" name="phoneTypeWorkPager" />
+  <java-symbol type="string" name="pm" />
+  <java-symbol type="string" name="policydesc_disableCamera" />
+  <java-symbol type="string" name="policydesc_encryptedStorage" />
+  <java-symbol type="string" name="policydesc_expirePassword" />
+  <java-symbol type="string" name="policydesc_forceLock" />
+  <java-symbol type="string" name="policydesc_limitPassword" />
+  <java-symbol type="string" name="policydesc_resetPassword" />
+  <java-symbol type="string" name="policydesc_setGlobalProxy" />
+  <java-symbol type="string" name="policydesc_watchLogin" />
+  <java-symbol type="string" name="policydesc_wipeData" />
+  <java-symbol type="string" name="policylab_disableCamera" />
+  <java-symbol type="string" name="policylab_encryptedStorage" />
+  <java-symbol type="string" name="policylab_expirePassword" />
+  <java-symbol type="string" name="policylab_forceLock" />
+  <java-symbol type="string" name="policylab_limitPassword" />
+  <java-symbol type="string" name="policylab_resetPassword" />
+  <java-symbol type="string" name="policylab_setGlobalProxy" />
+  <java-symbol type="string" name="policylab_watchLogin" />
+  <java-symbol type="string" name="policylab_wipeData" />
+  <java-symbol type="string" name="postalTypeCustom" />
+  <java-symbol type="string" name="postalTypeHome" />
+  <java-symbol type="string" name="postalTypeOther" />
+  <java-symbol type="string" name="postalTypeWork" />
+  <java-symbol type="string" name="power_off" />
+  <java-symbol type="string" name="preposition_for_date" />
+  <java-symbol type="string" name="preposition_for_time" />
+  <java-symbol type="string" name="progress_erasing" />
+  <java-symbol type="string" name="progress_unmounting" />
+  <java-symbol type="string" name="radiobutton_not_selected" />
+  <java-symbol type="string" name="radiobutton_selected" />
+  <java-symbol type="string" name="relationTypeAssistant" />
+  <java-symbol type="string" name="relationTypeBrother" />
+  <java-symbol type="string" name="relationTypeChild" />
+  <java-symbol type="string" name="relationTypeDomesticPartner" />
+  <java-symbol type="string" name="relationTypeFather" />
+  <java-symbol type="string" name="relationTypeFriend" />
+  <java-symbol type="string" name="relationTypeManager" />
+  <java-symbol type="string" name="relationTypeMother" />
+  <java-symbol type="string" name="relationTypeParent" />
+  <java-symbol type="string" name="relationTypePartner" />
+  <java-symbol type="string" name="relationTypeReferredBy" />
+  <java-symbol type="string" name="relationTypeRelative" />
+  <java-symbol type="string" name="relationTypeSister" />
+  <java-symbol type="string" name="relationTypeSpouse" />
+  <java-symbol type="string" name="relative_time" />
+  <java-symbol type="string" name="reset" />
+  <java-symbol type="string" name="ringtone_default" />
+  <java-symbol type="string" name="ringtone_default_with_actual" />
+  <java-symbol type="string" name="ringtone_picker_title" />
+  <java-symbol type="string" name="ringtone_silent" />
+  <java-symbol type="string" name="ringtone_unknown" />
+  <java-symbol type="string" name="roamingText0" />
+  <java-symbol type="string" name="roamingText1" />
+  <java-symbol type="string" name="roamingText10" />
+  <java-symbol type="string" name="roamingText11" />
+  <java-symbol type="string" name="roamingText12" />
+  <java-symbol type="string" name="roamingText2" />
+  <java-symbol type="string" name="roamingText3" />
+  <java-symbol type="string" name="roamingText4" />
+  <java-symbol type="string" name="roamingText5" />
+  <java-symbol type="string" name="roamingText6" />
+  <java-symbol type="string" name="roamingText7" />
+  <java-symbol type="string" name="roamingText8" />
+  <java-symbol type="string" name="roamingText9" />
+  <java-symbol type="string" name="roamingTextSearching" />
+  <java-symbol type="string" name="same_month_md1_md2" />
+  <java-symbol type="string" name="same_month_md1_time1_md2_time2" />
+  <java-symbol type="string" name="same_month_mdy1_mdy2" />
+  <java-symbol type="string" name="same_month_mdy1_time1_mdy2_time2" />
+  <java-symbol type="string" name="same_month_wday1_md1_time1_wday2_md2_time2" />
+  <java-symbol type="string" name="same_month_wday1_md1_wday2_md2" />
+  <java-symbol type="string" name="same_month_wday1_mdy1_time1_wday2_mdy2_time2" />
+  <java-symbol type="string" name="same_month_wday1_mdy1_wday2_mdy2" />
+  <java-symbol type="string" name="same_year_md1_md2" />
+  <java-symbol type="string" name="same_year_md1_time1_md2_time2" />
+  <java-symbol type="string" name="same_year_mdy1_mdy2" />
+  <java-symbol type="string" name="same_year_mdy1_time1_mdy2_time2" />
+  <java-symbol type="string" name="same_year_wday1_md1_time1_wday2_md2_time2" />
+  <java-symbol type="string" name="same_year_wday1_md1_wday2_md2" />
+  <java-symbol type="string" name="same_year_wday1_mdy1_time1_wday2_mdy2_time2" />
+  <java-symbol type="string" name="same_year_wday1_mdy1_wday2_mdy2" />
+  <java-symbol type="string" name="save_password_label" />
+  <java-symbol type="string" name="save_password_message" />
+  <java-symbol type="string" name="save_password_never" />
+  <java-symbol type="string" name="save_password_notnow" />
+  <java-symbol type="string" name="save_password_remember" />
+  <java-symbol type="string" name="sendText" />
+  <java-symbol type="string" name="sending" />
+  <java-symbol type="string" name="serviceClassData" />
+  <java-symbol type="string" name="serviceClassDataAsync" />
+  <java-symbol type="string" name="serviceClassDataSync" />
+  <java-symbol type="string" name="serviceClassFAX" />
+  <java-symbol type="string" name="serviceClassPAD" />
+  <java-symbol type="string" name="serviceClassPacket" />
+  <java-symbol type="string" name="serviceClassSMS" />
+  <java-symbol type="string" name="serviceClassVoice" />
+  <java-symbol type="string" name="serviceDisabled" />
+  <java-symbol type="string" name="serviceEnabled" />
+  <java-symbol type="string" name="serviceEnabledFor" />
+  <java-symbol type="string" name="serviceErased" />
+  <java-symbol type="string" name="serviceNotProvisioned" />
+  <java-symbol type="string" name="serviceRegistered" />
+  <java-symbol type="string" name="setup_autofill" />
+  <java-symbol type="string" name="shareactionprovider_share_with" />
+  <java-symbol type="string" name="shareactionprovider_share_with_application" />
+  <java-symbol type="string" name="short_format_month" />
+  <java-symbol type="string" name="shutdown_confirm" />
+  <java-symbol type="string" name="shutdown_confirm_question" />
+  <java-symbol type="string" name="shutdown_progress" />
+  <java-symbol type="string" name="sim_added_message" />
+  <java-symbol type="string" name="sim_added_title" />
+  <java-symbol type="string" name="sim_removed_message" />
+  <java-symbol type="string" name="sim_removed_title" />
+  <java-symbol type="string" name="sim_restart_button" />
+  <java-symbol type="string" name="sipAddressTypeCustom" />
+  <java-symbol type="string" name="sipAddressTypeHome" />
+  <java-symbol type="string" name="sipAddressTypeOther" />
+  <java-symbol type="string" name="sipAddressTypeWork" />
+  <java-symbol type="string" name="sms_control_default_app_name" />
+  <java-symbol type="string" name="sms_control_message" />
+  <java-symbol type="string" name="sms_control_no" />
+  <java-symbol type="string" name="sms_control_title" />
+  <java-symbol type="string" name="sms_control_yes" />
+  <java-symbol type="string" name="submit" />
+  <java-symbol type="string" name="switch_off" />
+  <java-symbol type="string" name="switch_on" />
+  <java-symbol type="string" name="sync_binding_label" />
+  <java-symbol type="string" name="sync_do_nothing" />
+  <java-symbol type="string" name="sync_really_delete" />
+  <java-symbol type="string" name="sync_too_many_deletes_desc" />
+  <java-symbol type="string" name="sync_undo_deletes" />
+  <java-symbol type="string" name="terabyteShort" />
+  <java-symbol type="string" name="text_copied" />
+  <java-symbol type="string" name="time1_time2" />
+  <java-symbol type="string" name="time_date" />
+  <java-symbol type="string" name="time_of_day" />
+  <java-symbol type="string" name="time_picker_decrement_hour_button" />
+  <java-symbol type="string" name="time_picker_decrement_minute_button" />
+  <java-symbol type="string" name="time_picker_decrement_set_am_button" />
+  <java-symbol type="string" name="time_picker_dialog_title" />
+  <java-symbol type="string" name="time_picker_increment_hour_button" />
+  <java-symbol type="string" name="time_picker_increment_minute_button" />
+  <java-symbol type="string" name="time_picker_increment_set_pm_button" />
+  <java-symbol type="string" name="time_picker_separator" />
+  <java-symbol type="string" name="time_wday" />
+  <java-symbol type="string" name="time_wday_date" />
+  <java-symbol type="string" name="today" />
+  <java-symbol type="string" name="togglebutton_not_pressed" />
+  <java-symbol type="string" name="togglebutton_pressed" />
+  <java-symbol type="string" name="tomorrow" />
+  <java-symbol type="string" name="twelve_hour_time_format" />
+  <java-symbol type="string" name="twenty_four_hour_time_format" />
+  <java-symbol type="string" name="upload_file" />
+  <java-symbol type="string" name="volume_alarm" />
+  <java-symbol type="string" name="volume_icon_description_bluetooth" />
+  <java-symbol type="string" name="volume_icon_description_incall" />
+  <java-symbol type="string" name="volume_icon_description_media" />
+  <java-symbol type="string" name="volume_icon_description_notification" />
+  <java-symbol type="string" name="volume_icon_description_ringer" />
+  <java-symbol type="string" name="wait" />
+  <java-symbol type="string" name="wday1_date1_time1_wday2_date2_time2" />
+  <java-symbol type="string" name="wday1_date1_wday2_date2" />
+  <java-symbol type="string" name="wday_date" />
+  <java-symbol type="string" name="web_user_agent" />
+  <java-symbol type="string" name="web_user_agent_target_content" />
+  <java-symbol type="string" name="webpage_unresponsive" />
+  <java-symbol type="string" name="whichApplication" />
+  <java-symbol type="string" name="wifi_available_sign_in" />
+  <java-symbol type="string" name="wifi_available_sign_in_detailed" />
+  <java-symbol type="string" name="wifi_p2p_dialog_title" />
+  <java-symbol type="string" name="wifi_p2p_enabled_notification_message" />
+  <java-symbol type="string" name="wifi_p2p_enabled_notification_title" />
+  <java-symbol type="string" name="wifi_p2p_failed_message" />
+  <java-symbol type="string" name="wifi_p2p_from_message" />
+  <java-symbol type="string" name="wifi_p2p_invitation_sent_title" />
+  <java-symbol type="string" name="wifi_p2p_invitation_to_connect_title" />
+  <java-symbol type="string" name="wifi_p2p_show_pin_message" />
+  <java-symbol type="string" name="wifi_p2p_to_message" />
+  <java-symbol type="string" name="wifi_p2p_turnon_message" />
+  <java-symbol type="string" name="wifi_tether_configure_ssid_default" />
+  <java-symbol type="string" name="wifi_watchdog_network_disabled" />
+  <java-symbol type="string" name="wifi_watchdog_network_disabled_detailed" />
+  <java-symbol type="string" name="yesterday" />
+
+  <java-symbol type="plurals" name="abbrev_in_num_days" />
+  <java-symbol type="plurals" name="abbrev_in_num_hours" />
+  <java-symbol type="plurals" name="abbrev_in_num_minutes" />
+  <java-symbol type="plurals" name="abbrev_in_num_seconds" />
+  <java-symbol type="plurals" name="abbrev_num_days_ago" />
+  <java-symbol type="plurals" name="abbrev_num_hours_ago" />
+  <java-symbol type="plurals" name="abbrev_num_minutes_ago" />
+  <java-symbol type="plurals" name="abbrev_num_seconds_ago" />
+  <java-symbol type="plurals" name="in_num_days" />
+  <java-symbol type="plurals" name="in_num_hours" />
+  <java-symbol type="plurals" name="in_num_minutes" />
+  <java-symbol type="plurals" name="in_num_seconds" />
+  <java-symbol type="plurals" name="last_num_days" />
+  <java-symbol type="plurals" name="matches_found" />
+  <java-symbol type="plurals" name="num_days_ago" />
+  <java-symbol type="plurals" name="num_hours_ago" />
+  <java-symbol type="plurals" name="num_minutes_ago" />
+  <java-symbol type="plurals" name="num_seconds_ago" />
+
+  <java-symbol type="array" name="carrier_properties" />
+  <java-symbol type="array" name="config_data_usage_network_types" />
+  <java-symbol type="array" name="config_sms_enabled_locking_shift_tables" />
+  <java-symbol type="array" name="config_sms_enabled_single_shift_tables" />
+  <java-symbol type="array" name="config_twoDigitNumberPattern" />
+  <java-symbol type="array" name="networkAttributes" />
+  <java-symbol type="array" name="preloaded_color_state_lists" />
+  <java-symbol type="array" name="preloaded_drawables" />
+  <java-symbol type="array" name="special_locale_codes" />
+  <java-symbol type="array" name="special_locale_names" />
+  <java-symbol type="array" name="config_masterVolumeRamp" />
+
+  <java-symbol type="drawable" name="default_wallpaper" />
+  <java-symbol type="drawable" name="ic_suggestions_add" />
+  <java-symbol type="drawable" name="ic_suggestions_delete" />
+  <java-symbol type="drawable" name="indicator_input_error" />
+  <java-symbol type="drawable" name="overscroll_edge" />
+  <java-symbol type="drawable" name="overscroll_glow" />
+  <java-symbol type="drawable" name="popup_bottom_dark" />
+  <java-symbol type="drawable" name="popup_bottom_bright" />
+  <java-symbol type="drawable" name="popup_bottom_medium" />
+  <java-symbol type="drawable" name="popup_center_dark" />
+  <java-symbol type="drawable" name="popup_center_bright" />
+  <java-symbol type="drawable" name="popup_full_dark" />
+  <java-symbol type="drawable" name="popup_full_bright" />
+  <java-symbol type="drawable" name="popup_top_dark" />
+  <java-symbol type="drawable" name="popup_top_bright" />
+  <java-symbol type="drawable" name="search_spinner" />
+  <java-symbol type="drawable" name="sym_app_on_sd_unavailable_icon" />
+  <java-symbol type="drawable" name="text_edit_side_paste_window" />
+  <java-symbol type="drawable" name="text_edit_paste_window" />
+  <java-symbol type="drawable" name="btn_check_off" />
+  <java-symbol type="drawable" name="btn_code_lock_default_holo" />
+  <java-symbol type="drawable" name="btn_code_lock_touched_holo" />
+  <java-symbol type="drawable" name="clock_dial" />
+  <java-symbol type="drawable" name="clock_hand_hour" />
+  <java-symbol type="drawable" name="clock_hand_minute" />
+  <java-symbol type="drawable" name="emo_im_angel" />
+  <java-symbol type="drawable" name="emo_im_cool" />
+  <java-symbol type="drawable" name="emo_im_crying" />
+  <java-symbol type="drawable" name="emo_im_embarrassed" />
+  <java-symbol type="drawable" name="emo_im_foot_in_mouth" />
+  <java-symbol type="drawable" name="emo_im_happy" />
+  <java-symbol type="drawable" name="emo_im_kissing" />
+  <java-symbol type="drawable" name="emo_im_laughing" />
+  <java-symbol type="drawable" name="emo_im_lips_are_sealed" />
+  <java-symbol type="drawable" name="emo_im_money_mouth" />
+  <java-symbol type="drawable" name="emo_im_sad" />
+  <java-symbol type="drawable" name="emo_im_surprised" />
+  <java-symbol type="drawable" name="emo_im_tongue_sticking_out" />
+  <java-symbol type="drawable" name="emo_im_undecided" />
+  <java-symbol type="drawable" name="emo_im_winking" />
+  <java-symbol type="drawable" name="emo_im_wtf" />
+  <java-symbol type="drawable" name="emo_im_yelling" />
+  <java-symbol type="drawable" name="expander_close_holo_dark" />
+  <java-symbol type="drawable" name="expander_open_holo_dark" />
+  <java-symbol type="drawable" name="ic_audio_alarm" />
+  <java-symbol type="drawable" name="ic_audio_alarm_mute" />
+  <java-symbol type="drawable" name="ic_audio_bt" />
+  <java-symbol type="drawable" name="ic_audio_bt_mute" />
+  <java-symbol type="drawable" name="ic_audio_notification" />
+  <java-symbol type="drawable" name="ic_audio_notification_mute" />
+  <java-symbol type="drawable" name="ic_audio_phone" />
+  <java-symbol type="drawable" name="ic_audio_ring_notif" />
+  <java-symbol type="drawable" name="ic_audio_ring_notif_mute" />
+  <java-symbol type="drawable" name="ic_audio_ring_notif_vibrate" />
+  <java-symbol type="drawable" name="ic_audio_vol" />
+  <java-symbol type="drawable" name="ic_audio_vol_mute" />
+  <java-symbol type="drawable" name="ic_bullet_key_permission" />
+  <java-symbol type="drawable" name="ic_contact_picture" />
+  <java-symbol type="drawable" name="ic_dialog_usb" />
+  <java-symbol type="drawable" name="ic_emergency" />
+  <java-symbol type="drawable" name="ic_media_stop" />
+  <java-symbol type="drawable" name="ic_text_dot" />
+  <java-symbol type="drawable" name="indicator_code_lock_drag_direction_green_up" />
+  <java-symbol type="drawable" name="indicator_code_lock_drag_direction_red_up" />
+  <java-symbol type="drawable" name="indicator_code_lock_point_area_default_holo" />
+  <java-symbol type="drawable" name="indicator_code_lock_point_area_green_holo" />
+  <java-symbol type="drawable" name="indicator_code_lock_point_area_red_holo" />
+  <java-symbol type="drawable" name="jog_dial_arrow_long_left_green" />
+  <java-symbol type="drawable" name="jog_dial_arrow_long_right_red" />
+  <java-symbol type="drawable" name="jog_dial_arrow_short_left_and_right" />
+  <java-symbol type="drawable" name="jog_dial_bg" />
+  <java-symbol type="drawable" name="jog_dial_dimple" />
+  <java-symbol type="drawable" name="jog_dial_dimple_dim" />
+  <java-symbol type="drawable" name="jog_tab_bar_left_generic" />
+  <java-symbol type="drawable" name="jog_tab_bar_right_generic" />
+  <java-symbol type="drawable" name="jog_tab_left_generic" />
+  <java-symbol type="drawable" name="jog_tab_right_generic" />
+  <java-symbol type="drawable" name="jog_tab_target_gray" />
+  <java-symbol type="drawable" name="picture_emergency" />
+  <java-symbol type="drawable" name="platlogo" />
+  <java-symbol type="drawable" name="stat_notify_sync_error" />
+  <java-symbol type="drawable" name="stat_notify_wifi_in_range" />
+  <java-symbol type="drawable" name="stat_sys_gps_on" />
+  <java-symbol type="drawable" name="stat_sys_tether_wifi" />
+  <java-symbol type="drawable" name="status_bar_background" />
+  <java-symbol type="drawable" name="sym_keyboard_shift" />
+  <java-symbol type="drawable" name="sym_keyboard_shift_locked" />
+  <java-symbol type="drawable" name="tab_bottom_left" />
+  <java-symbol type="drawable" name="tab_bottom_left_v4" />
+  <java-symbol type="drawable" name="tab_bottom_right" />
+  <java-symbol type="drawable" name="tab_bottom_right_v4" />
+  <java-symbol type="drawable" name="tab_indicator_v4" />
+  <java-symbol type="drawable" name="text_select_handle_left" />
+  <java-symbol type="drawable" name="text_select_handle_right" />
+  <java-symbol type="drawable" name="unknown_image" />
+  <java-symbol type="drawable" name="unlock_default" />
+  <java-symbol type="drawable" name="unlock_halo" />
+  <java-symbol type="drawable" name="unlock_ring" />
+  <java-symbol type="drawable" name="unlock_wave" />
+
+  <java-symbol type="layout" name="action_bar_home" />
+  <java-symbol type="layout" name="action_bar_title_item" />
+  <java-symbol type="layout" name="action_menu_item_layout" />
+  <java-symbol type="layout" name="action_menu_layout" />
+  <java-symbol type="layout" name="action_mode_close_item" />
+  <java-symbol type="layout" name="alert_dialog" />
+  <java-symbol type="layout" name="choose_account" />
+  <java-symbol type="layout" name="choose_account_row" />
+  <java-symbol type="layout" name="choose_account_type" />
+  <java-symbol type="layout" name="choose_selected_account_row" />
+  <java-symbol type="layout" name="choose_type_and_account" />
+  <java-symbol type="layout" name="grant_credentials_permission" />
+  <java-symbol type="layout" name="number_picker" />
+  <java-symbol type="layout" name="permissions_package_list_item" />
+  <java-symbol type="layout" name="popup_menu_item_layout" />
+  <java-symbol type="layout" name="remote_views_adapter_default_loading_view" />
+  <java-symbol type="layout" name="search_bar" />
+  <java-symbol type="layout" name="search_dropdown_item_icons_2line" />
+  <java-symbol type="layout" name="search_view" />
+  <java-symbol type="layout" name="select_dialog" />
+  <java-symbol type="layout" name="simple_dropdown_hint" />
+  <java-symbol type="layout" name="status_bar_latest_event_content" />
+  <java-symbol type="layout" name="status_bar_latest_event_content_large_icon" />
+  <java-symbol type="layout" name="status_bar_latest_event_ticker" />
+  <java-symbol type="layout" name="status_bar_latest_event_ticker_large_icon" />
+  <java-symbol type="layout" name="text_edit_action_popup_text" />
+  <java-symbol type="layout" name="text_drag_thumbnail" />
+  <java-symbol type="layout" name="typing_filter" />
+  <java-symbol type="layout" name="activity_chooser_view" />
+  <java-symbol type="layout" name="activity_chooser_view_list_item" />
+  <java-symbol type="layout" name="activity_list" />
+  <java-symbol type="layout" name="activity_list_item_2" />
+  <java-symbol type="layout" name="alert_dialog_progress" />
+  <java-symbol type="layout" name="always_use_checkbox" />
+  <java-symbol type="layout" name="app_permission_item" />
+  <java-symbol type="layout" name="app_perms_summary" />
+  <java-symbol type="layout" name="calendar_view" />
+  <java-symbol type="layout" name="character_picker" />
+  <java-symbol type="layout" name="character_picker_button" />
+  <java-symbol type="layout" name="date_picker" />
+  <java-symbol type="layout" name="date_picker_dialog" />
+  <java-symbol type="layout" name="expanded_menu_layout" />
+  <java-symbol type="layout" name="fragment_bread_crumb_item" />
+  <java-symbol type="layout" name="fragment_bread_crumbs" />
+  <java-symbol type="layout" name="heavy_weight_switcher" />
+  <java-symbol type="layout" name="icon_menu_item_layout" />
+  <java-symbol type="layout" name="icon_menu_layout" />
+  <java-symbol type="layout" name="input_method" />
+  <java-symbol type="layout" name="input_method_extract_view" />
+  <java-symbol type="layout" name="js_prompt" />
+  <java-symbol type="layout" name="list_content_simple" />
+  <java-symbol type="layout" name="list_menu_item_checkbox" />
+  <java-symbol type="layout" name="list_menu_item_icon" />
+  <java-symbol type="layout" name="list_menu_item_layout" />
+  <java-symbol type="layout" name="list_menu_item_radio" />
+  <java-symbol type="layout" name="locale_picker_item" />
+  <java-symbol type="layout" name="media_controller" />
+  <java-symbol type="layout" name="preference" />
+  <java-symbol type="layout" name="preference_header_item" />
+  <java-symbol type="layout" name="preference_list_content" />
+  <java-symbol type="layout" name="preference_list_content_single" />
+  <java-symbol type="layout" name="preference_list_fragment" />
+  <java-symbol type="layout" name="preference_widget_seekbar" />
+  <java-symbol type="layout" name="progress_dialog" />
+  <java-symbol type="layout" name="resolve_list_item" />
+  <java-symbol type="layout" name="seekbar_dialog" />
+  <java-symbol type="layout" name="select_dialog_singlechoice_holo" />
+  <java-symbol type="layout" name="ssl_certificate" />
+  <java-symbol type="layout" name="tab_content" />
+  <java-symbol type="layout" name="tab_indicator_holo" />
+  <java-symbol type="layout" name="textview_hint" />
+  <java-symbol type="layout" name="time_picker" />
+  <java-symbol type="layout" name="time_picker_dialog" />
+  <java-symbol type="layout" name="transient_notification" />
+  <java-symbol type="layout" name="volume_adjust" />
+  <java-symbol type="layout" name="volume_adjust_item" />
+  <java-symbol type="layout" name="web_text_view_dropdown" />
+  <java-symbol type="layout" name="webview_find" />
+  <java-symbol type="layout" name="webview_select_singlechoice" />
+  <java-symbol type="layout" name="wifi_p2p_dialog" />
+  <java-symbol type="layout" name="wifi_p2p_dialog_row" />
+  <java-symbol type="layout" name="zoom_container" />
+  <java-symbol type="layout" name="zoom_controls" />
+  <java-symbol type="layout" name="zoom_magnify" />
+
+  <java-symbol type="anim" name="slide_in_child_bottom" />
+  <java-symbol type="anim" name="slide_in_right" />
+  <java-symbol type="anim" name="slide_out_left" />
+
+  <java-symbol type="menu" name="webview_copy" />
+  <java-symbol type="menu" name="webview_find" />
+
+  <java-symbol type="xml" name="password_kbd_qwerty" />
+  <java-symbol type="xml" name="autotext" />
+  <java-symbol type="xml" name="eri" />
+  <java-symbol type="xml" name="password_kbd_numeric" />
+  <java-symbol type="xml" name="password_kbd_qwerty_shifted" />
+  <java-symbol type="xml" name="password_kbd_symbols" />
+  <java-symbol type="xml" name="password_kbd_symbols_shift" />
+  <java-symbol type="xml" name="power_profile" />
+  <java-symbol type="xml" name="time_zones_by_country" />
+
+  <java-symbol type="raw" name="incognito_mode_start_page" />
+  <java-symbol type="raw" name="loaderror" />
+  <java-symbol type="raw" name="nodomain" />
+
+  <java-symbol type="style" name="Animation.DropDownUp" />
+  <java-symbol type="style" name="Animation.DropDownDown" />
+  <java-symbol type="style" name="Animation.PopupWindow" />
+  <java-symbol type="style" name="Animation.TypingFilter" />
+  <java-symbol type="style" name="Animation.TypingFilterRestore" />
+  <java-symbol type="style" name="Theme.DeviceDefault.Dialog.Alert" />
+  <java-symbol type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />
+  <java-symbol type="style" name="Theme.Dialog.Alert" />
+  <java-symbol type="style" name="Theme.Holo.Dialog.Alert" />
+  <java-symbol type="style" name="Theme.Holo.Light.Dialog.Alert" />
+  <java-symbol type="style" name="ActiveWallpaperSettings" />
+  <java-symbol type="style" name="Animation.InputMethodFancy" />
+  <java-symbol type="style" name="Animation.Wallpaper" />
+  <java-symbol type="style" name="Animation.RecentApplications" />
+  <java-symbol type="style" name="Animation.ZoomButtons" />
+  <java-symbol type="style" name="PreviewWallpaperSettings" />
+  <java-symbol type="style" name="TextAppearance.SlidingTabActive" />
+  <java-symbol type="style" name="TextAppearance.SlidingTabNormal" />
+  <java-symbol type="style" name="Theme.DeviceDefault.Dialog.NoFrame" />
+  <java-symbol type="style" name="Theme.IconMenu" />
+  <java-symbol type="style" name="Theme.Panel.Volume" />
+
+  <!-- From android.policy -->
+  <java-symbol type="anim" name="app_starting_exit" />
+  <java-symbol type="anim" name="lock_screen_behind_enter" />
+  <java-symbol type="array" name="config_keyboardTapVibePattern" />
+  <java-symbol type="array" name="config_longPressVibePattern" />
+  <java-symbol type="array" name="config_safeModeDisabledVibePattern" />
+  <java-symbol type="array" name="config_safeModeEnabledVibePattern" />
+  <java-symbol type="array" name="config_virtualKeyVibePattern" />
+  <java-symbol type="array" name="lockscreen_targets_when_silent" />
+  <java-symbol type="array" name="lockscreen_targets_when_soundon" />
+  <java-symbol type="array" name="lockscreen_targets_with_camera" />
+  <java-symbol type="attr" name="actionModePopupWindowStyle" />
+  <java-symbol type="attr" name="dialogCustomTitleDecorLayout" />
+  <java-symbol type="attr" name="dialogTitleDecorLayout" />
+  <java-symbol type="attr" name="dialogTitleIconsDecorLayout" />
+  <java-symbol type="bool" name="config_allowAllRotations" />
+  <java-symbol type="bool" name="config_bypass_keyguard_if_slider_open" />
+  <java-symbol type="bool" name="config_carDockEnablesAccelerometer" />
+  <java-symbol type="bool" name="config_deskDockEnablesAccelerometer" />
+  <java-symbol type="bool" name="config_disableMenuKeyInLockScreen" />
+  <java-symbol type="bool" name="config_enableLockBeforeUnlockScreen" />
+  <java-symbol type="bool" name="config_enableLockScreenRotation" />
+  <java-symbol type="bool" name="config_reverseDefaultRotation" />
+  <java-symbol type="bool" name="config_showNavigationBar" />
+  <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
+  <java-symbol type="dimen" name="navigation_bar_height" />
+  <java-symbol type="dimen" name="navigation_bar_width" />
+  <java-symbol type="dimen" name="status_bar_height" />
+  <java-symbol type="dimen" name="system_bar_height" />
+  <java-symbol type="drawable" name="ic_jog_dial_sound_off" />
+  <java-symbol type="drawable" name="ic_jog_dial_sound_on" />
+  <java-symbol type="drawable" name="ic_jog_dial_unlock" />
+  <java-symbol type="drawable" name="ic_jog_dial_vibrate_on" />
+  <java-symbol type="drawable" name="ic_lock_airplane_mode" />
+  <java-symbol type="drawable" name="ic_lock_airplane_mode_off" />
+  <java-symbol type="drawable" name="ic_menu_cc" />
+  <java-symbol type="drawable" name="jog_tab_bar_left_unlock" />
+  <java-symbol type="drawable" name="jog_tab_bar_right_sound_off" />
+  <java-symbol type="drawable" name="jog_tab_bar_right_sound_on" />
+  <java-symbol type="drawable" name="jog_tab_left_unlock" />
+  <java-symbol type="drawable" name="jog_tab_right_sound_off" />
+  <java-symbol type="drawable" name="jog_tab_right_sound_on" />
+  <java-symbol type="drawable" name="jog_tab_target_green" />
+  <java-symbol type="drawable" name="jog_tab_target_yellow" />
+  <java-symbol type="drawable" name="menu_background" />
+  <java-symbol type="drawable" name="stat_sys_secure" />
+  <java-symbol type="id" name="action_mode_bar_stub" />
+  <java-symbol type="id" name="alarm_status" />
+  <java-symbol type="id" name="backspace" />
+  <java-symbol type="id" name="button0" />
+  <java-symbol type="id" name="button4" />
+  <java-symbol type="id" name="button5" />
+  <java-symbol type="id" name="button6" />
+  <java-symbol type="id" name="button7" />
+  <java-symbol type="id" name="carrier" />
+  <java-symbol type="id" name="date" />
+  <java-symbol type="id" name="eight" />
+  <java-symbol type="id" name="emergencyCallButton" />
+  <java-symbol type="id" name="faceLockAreaView" />
+  <java-symbol type="id" name="five" />
+  <java-symbol type="id" name="forgotPatternButton" />
+  <java-symbol type="id" name="four" />
+  <java-symbol type="id" name="headerText" />
+  <java-symbol type="id" name="icon_menu_presenter" />
+  <java-symbol type="id" name="instructions" />
+  <java-symbol type="id" name="keyboard" />
+  <java-symbol type="id" name="list_menu_presenter" />
+  <java-symbol type="id" name="lockPattern" />
+  <java-symbol type="id" name="lock_screen" />
+  <java-symbol type="id" name="login" />
+  <java-symbol type="id" name="nine" />
+  <java-symbol type="id" name="no_applications_message" />
+  <java-symbol type="id" name="ok" />
+  <java-symbol type="id" name="one" />
+  <java-symbol type="id" name="option1" />
+  <java-symbol type="id" name="option2" />
+  <java-symbol type="id" name="option3" />
+  <java-symbol type="id" name="password" />
+  <java-symbol type="id" name="passwordEntry" />
+  <java-symbol type="id" name="pinDel" />
+  <java-symbol type="id" name="pinDisplay" />
+  <java-symbol type="id" name="propertyOf" />
+  <java-symbol type="id" name="pukDel" />
+  <java-symbol type="id" name="pukDisplay" />
+  <java-symbol type="id" name="right_icon" />
+  <java-symbol type="id" name="seven" />
+  <java-symbol type="id" name="six" />
+  <java-symbol type="id" name="status" />
+  <java-symbol type="id" name="status1" />
+  <java-symbol type="id" name="switch_ime_button" />
+  <java-symbol type="id" name="three" />
+  <java-symbol type="id" name="title_container" />
+  <java-symbol type="id" name="topHeader" />
+  <java-symbol type="id" name="transport" />
+  <java-symbol type="id" name="transport_bg_protect" />
+  <java-symbol type="id" name="two" />
+  <java-symbol type="id" name="unlock_widget" />
+  <java-symbol type="id" name="zero" />
+  <java-symbol type="integer" name="config_carDockRotation" />
+  <java-symbol type="integer" name="config_defaultUiModeType" />
+  <java-symbol type="integer" name="config_deskDockRotation" />
+  <java-symbol type="integer" name="config_lidKeyboardAccessibility" />
+  <java-symbol type="integer" name="config_lidNavigationAccessibility" />
+  <java-symbol type="integer" name="config_lidOpenRotation" />
+  <java-symbol type="integer" name="config_longPressOnHomeBehavior" />
+  <java-symbol type="layout" name="global_actions_item" />
+  <java-symbol type="layout" name="global_actions_silent_mode" />
+  <java-symbol type="layout" name="keyguard_screen_glogin_unlock" />
+  <java-symbol type="layout" name="keyguard_screen_password_landscape" />
+  <java-symbol type="layout" name="keyguard_screen_password_portrait" />
+  <java-symbol type="layout" name="keyguard_screen_sim_pin_landscape" />
+  <java-symbol type="layout" name="keyguard_screen_sim_pin_portrait" />
+  <java-symbol type="layout" name="keyguard_screen_sim_puk_landscape" />
+  <java-symbol type="layout" name="keyguard_screen_sim_puk_portrait" />
+  <java-symbol type="layout" name="keyguard_screen_tab_unlock" />
+  <java-symbol type="layout" name="keyguard_screen_tab_unlock_land" />
+  <java-symbol type="layout" name="keyguard_screen_unlock_landscape" />
+  <java-symbol type="layout" name="keyguard_screen_unlock_portrait" />
+  <java-symbol type="layout" name="recent_apps_dialog" />
+  <java-symbol type="layout" name="screen_action_bar" />
+  <java-symbol type="layout" name="screen_action_bar_overlay" />
+  <java-symbol type="layout" name="screen_custom_title" />
+  <java-symbol type="layout" name="screen_progress" />
+  <java-symbol type="layout" name="screen_simple" />
+  <java-symbol type="layout" name="screen_simple_overlay_action_mode" />
+  <java-symbol type="layout" name="screen_title" />
+  <java-symbol type="layout" name="screen_title_icons" />
+  <java-symbol type="string" name="abbrev_wday_month_day_no_year" />
+  <java-symbol type="string" name="android_upgrading_title" />
+  <java-symbol type="string" name="config_defaultDreamComponent" />
+  <java-symbol type="string" name="faceunlock_multiple_failures" />
+  <java-symbol type="string" name="global_action_power_off" />
+  <java-symbol type="string" name="global_actions_airplane_mode_off_status" />
+  <java-symbol type="string" name="global_actions_airplane_mode_on_status" />
+  <java-symbol type="string" name="global_actions_toggle_airplane_mode" />
+  <java-symbol type="string" name="invalidPuk" />
+  <java-symbol type="string" name="keyguard_password_enter_pin_code" />
+  <java-symbol type="string" name="keyguard_password_enter_puk_code" />
+  <java-symbol type="string" name="keyguard_password_wrong_pin_code" />
+  <java-symbol type="string" name="lockscreen_carrier_default" />
+  <java-symbol type="string" name="lockscreen_charged" />
+  <java-symbol type="string" name="lockscreen_failed_attempts_almost_at_wipe" />
+  <java-symbol type="string" name="lockscreen_failed_attempts_almost_glogin" />
+  <java-symbol type="string" name="lockscreen_failed_attempts_now_wiping" />
+  <java-symbol type="string" name="lockscreen_forgot_pattern_button_text" />
+  <java-symbol type="string" name="lockscreen_glogin_checking_password" />
+  <java-symbol type="string" name="lockscreen_glogin_forgot_pattern" />
+  <java-symbol type="string" name="lockscreen_glogin_invalid_input" />
+  <java-symbol type="string" name="lockscreen_glogin_too_many_attempts" />
+  <java-symbol type="string" name="lockscreen_instructions_when_pattern_disabled" />
+  <java-symbol type="string" name="lockscreen_low_battery" />
+  <java-symbol type="string" name="lockscreen_missing_sim_instructions" />
+  <java-symbol type="string" name="lockscreen_missing_sim_instructions_long" />
+  <java-symbol type="string" name="lockscreen_missing_sim_message_short" />
+  <java-symbol type="string" name="lockscreen_network_locked_message" />
+  <java-symbol type="string" name="lockscreen_password_wrong" />
+  <java-symbol type="string" name="lockscreen_pattern_instructions" />
+  <java-symbol type="string" name="lockscreen_pattern_wrong" />
+  <java-symbol type="string" name="lockscreen_permanent_disabled_sim_instructions" />
+  <java-symbol type="string" name="lockscreen_plugged_in" />
+  <java-symbol type="string" name="lockscreen_sim_locked_message" />
+  <java-symbol type="string" name="lockscreen_sim_puk_locked_message" />
+  <java-symbol type="string" name="lockscreen_sim_unlock_progress_dialog_message" />
+  <java-symbol type="string" name="lockscreen_sound_off_label" />
+  <java-symbol type="string" name="lockscreen_sound_on_label" />
+  <java-symbol type="string" name="lockscreen_too_many_failed_attempts_countdown" />
+  <java-symbol type="string" name="lockscreen_too_many_failed_attempts_dialog_message" />
+  <java-symbol type="string" name="lockscreen_too_many_failed_password_attempts_dialog_message" />
+  <java-symbol type="string" name="lockscreen_too_many_failed_pin_attempts_dialog_message" />
+  <java-symbol type="string" name="lockscreen_unlock_label" />
+  <java-symbol type="string" name="status_bar_device_locked" />
+  <java-symbol type="style" name="Animation.LockScreen" />
+  <java-symbol type="style" name="Theme.Dialog.RecentApplications" />
+  <java-symbol type="style" name="Theme.ExpandedMenu" />
+
+  <!-- From services -->
+  <java-symbol type="anim" name="screen_rotate_0_enter" />
+  <java-symbol type="anim" name="screen_rotate_0_exit" />
+  <java-symbol type="anim" name="screen_rotate_180_enter" />
+  <java-symbol type="anim" name="screen_rotate_180_exit" />
+  <java-symbol type="anim" name="screen_rotate_finish_enter" />
+  <java-symbol type="anim" name="screen_rotate_finish_exit" />
+  <java-symbol type="anim" name="screen_rotate_minus_90_enter" />
+  <java-symbol type="anim" name="screen_rotate_minus_90_exit" />
+  <java-symbol type="anim" name="screen_rotate_plus_90_enter" />
+  <java-symbol type="anim" name="screen_rotate_plus_90_exit" />
+  <java-symbol type="anim" name="screen_rotate_start_enter" />
+  <java-symbol type="anim" name="screen_rotate_start_exit" />
+  <java-symbol type="anim" name="window_move_from_decor" />
+  <java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" />
+  <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
+  <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
+  <java-symbol type="array" name="config_autoBrightnessLevels" />
+  <java-symbol type="array" name="config_protectedNetworks" />
+  <java-symbol type="array" name="config_statusBarIcons" />
+  <java-symbol type="array" name="config_tether_bluetooth_regexs" />
+  <java-symbol type="array" name="config_tether_dhcp_range" />
+  <java-symbol type="array" name="config_tether_upstream_types" />
+  <java-symbol type="array" name="config_tether_usb_regexs" />
+  <java-symbol type="array" name="config_tether_wifi_regexs" />
+  <java-symbol type="array" name="config_usbHostBlacklist" />
+  <java-symbol type="array" name="config_serialPorts" />
+  <java-symbol type="array" name="radioAttributes" />
+  <java-symbol type="array" name="config_oemUsbModeOverride" />
+  <java-symbol type="bool" name="config_animateScreenLights" />
+  <java-symbol type="bool" name="config_automatic_brightness_available" />
+  <java-symbol type="bool" name="config_sf_limitedAlpha" />
+  <java-symbol type="bool" name="config_unplugTurnsOnScreen" />
+  <java-symbol type="bool" name="config_wifi_background_scan_support" />
+  <java-symbol type="bool" name="config_wifi_dual_band_support" />
+  <java-symbol type="bool" name="config_wimaxEnabled" />
+  <java-symbol type="bool" name="show_ongoing_ime_switcher" />
+  <java-symbol type="color" name="config_defaultNotificationColor" />
+  <java-symbol type="drawable" name="ic_notification_ime_default" />
+  <java-symbol type="drawable" name="stat_notify_car_mode" />
+  <java-symbol type="drawable" name="stat_notify_disabled" />
+  <java-symbol type="drawable" name="stat_notify_disk_full" />
+  <java-symbol type="drawable" name="stat_sys_adb" />
+  <java-symbol type="drawable" name="stat_sys_battery" />
+  <java-symbol type="drawable" name="stat_sys_battery_charge" />
+  <java-symbol type="drawable" name="stat_sys_battery_unknown" />
+  <java-symbol type="drawable" name="stat_sys_data_usb" />
+  <java-symbol type="drawable" name="stat_sys_tether_bluetooth" />
+  <java-symbol type="drawable" name="stat_sys_tether_general" />
+  <java-symbol type="drawable" name="stat_sys_tether_usb" />
+  <java-symbol type="drawable" name="stat_sys_throttled" />
+  <java-symbol type="drawable" name="vpn_connected" />
+  <java-symbol type="id" name="ask_checkbox" />
+  <java-symbol type="id" name="compat_checkbox" />
+  <java-symbol type="id" name="original_app_icon" />
+  <java-symbol type="id" name="original_message" />
+  <java-symbol type="id" name="radio" />
+  <java-symbol type="id" name="reask_hint" />
+  <java-symbol type="id" name="replace_app_icon" />
+  <java-symbol type="id" name="replace_message" />
+  <java-symbol type="fraction" name="config_dimBehindFadeDuration" />
+  <java-symbol type="integer" name="config_carDockKeepsScreenOn" />
+  <java-symbol type="integer" name="config_criticalBatteryWarningLevel" />
+  <java-symbol type="integer" name="config_datause_notification_type" />
+  <java-symbol type="integer" name="config_datause_polling_period_sec" />
+  <java-symbol type="integer" name="config_datause_threshold_bytes" />
+  <java-symbol type="integer" name="config_datause_throttle_kbitsps" />
+  <java-symbol type="integer" name="config_defaultNotificationLedOff" />
+  <java-symbol type="integer" name="config_defaultNotificationLedOn" />
+  <java-symbol type="integer" name="config_deskDockKeepsScreenOn" />
+  <java-symbol type="integer" name="config_lightSensorWarmupTime" />
+  <java-symbol type="integer" name="config_lowBatteryCloseWarningLevel" />
+  <java-symbol type="integer" name="config_lowBatteryWarningLevel" />
+  <java-symbol type="integer" name="config_networkPolicyDefaultWarning" />
+  <java-symbol type="integer" name="config_networkTransitionTimeout" />
+  <java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
+  <java-symbol type="integer" name="config_notificationsBatteryLedOff" />
+  <java-symbol type="integer" name="config_notificationsBatteryLedOn" />
+  <java-symbol type="integer" name="config_notificationsBatteryLowARGB" />
+  <java-symbol type="integer" name="config_notificationsBatteryMediumARGB" />
+  <java-symbol type="integer" name="config_radioScanningTimeout" />
+  <java-symbol type="integer" name="config_screenBrightnessDim" />
+  <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
+  <java-symbol type="layout" name="am_compat_mode_dialog" />
+  <java-symbol type="layout" name="launch_warning" />
+  <java-symbol type="layout" name="safe_mode" />
+  <java-symbol type="layout" name="simple_list_item_2_single_choice" />
+  <java-symbol type="plurals" name="wifi_available" />
+  <java-symbol type="plurals" name="wifi_available_detailed" />
+  <java-symbol type="string" name="accessibility_binding_label" />
+  <java-symbol type="string" name="adb_active_notification_message" />
+  <java-symbol type="string" name="adb_active_notification_title" />
+  <java-symbol type="string" name="aerr_application" />
+  <java-symbol type="string" name="aerr_process" />
+  <java-symbol type="string" name="aerr_title" />
+  <java-symbol type="string" name="android_upgrading_apk" />
+  <java-symbol type="string" name="android_upgrading_complete" />
+  <java-symbol type="string" name="android_upgrading_starting_apps" />
+  <java-symbol type="string" name="anr_activity_application" />
+  <java-symbol type="string" name="anr_activity_process" />
+  <java-symbol type="string" name="anr_application_process" />
+  <java-symbol type="string" name="anr_process" />
+  <java-symbol type="string" name="anr_title" />
+  <java-symbol type="string" name="car_mode_disable_notification_message" />
+  <java-symbol type="string" name="car_mode_disable_notification_title" />
+  <java-symbol type="string" name="chooser_wallpaper" />
+  <java-symbol type="string" name="config_datause_iface" />
+  <java-symbol type="string" name="config_geocodeProvider" />
+  <java-symbol type="string" name="config_networkLocationProvider" />
+  <java-symbol type="string" name="config_wimaxManagerClassname" />
+  <java-symbol type="string" name="config_wimaxNativeLibLocation" />
+  <java-symbol type="string" name="config_wimaxServiceClassname" />
+  <java-symbol type="string" name="config_wimaxServiceJarLocation" />
+  <java-symbol type="string" name="config_wimaxStateTrackerClassname" />
+  <java-symbol type="string" name="configure_input_methods" />
+  <java-symbol type="string" name="data_usage_3g_limit_snoozed_title" />
+  <java-symbol type="string" name="data_usage_3g_limit_title" />
+  <java-symbol type="string" name="data_usage_4g_limit_snoozed_title" />
+  <java-symbol type="string" name="data_usage_4g_limit_title" />
+  <java-symbol type="string" name="data_usage_limit_body" />
+  <java-symbol type="string" name="data_usage_limit_snoozed_body" />
+  <java-symbol type="string" name="data_usage_mobile_limit_snoozed_title" />
+  <java-symbol type="string" name="data_usage_mobile_limit_title" />
+  <java-symbol type="string" name="data_usage_restricted_body" />
+  <java-symbol type="string" name="data_usage_restricted_title" />
+  <java-symbol type="string" name="data_usage_warning_body" />
+  <java-symbol type="string" name="data_usage_warning_title" />
+  <java-symbol type="string" name="data_usage_wifi_limit_snoozed_title" />
+  <java-symbol type="string" name="data_usage_wifi_limit_title" />
+  <java-symbol type="string" name="default_wallpaper_component" />
+  <java-symbol type="string" name="dlg_ok" />
+  <java-symbol type="string" name="factorytest_failed" />
+  <java-symbol type="string" name="factorytest_no_action" />
+  <java-symbol type="string" name="factorytest_not_system" />
+  <java-symbol type="string" name="factorytest_reboot" />
+  <java-symbol type="string" name="heavy_weight_notification" />
+  <java-symbol type="string" name="heavy_weight_notification_detail" />
+  <java-symbol type="string" name="input_method_binding_label" />
+  <java-symbol type="string" name="launch_warning_original" />
+  <java-symbol type="string" name="launch_warning_replace" />
+  <java-symbol type="string" name="launch_warning_title" />
+  <java-symbol type="string" name="low_internal_storage_view_text" />
+  <java-symbol type="string" name="low_internal_storage_view_title" />
+  <java-symbol type="string" name="report" />
+  <java-symbol type="string" name="select_input_method" />
+  <java-symbol type="string" name="smv_application" />
+  <java-symbol type="string" name="smv_process" />
+  <java-symbol type="string" name="tethered_notification_message" />
+  <java-symbol type="string" name="tethered_notification_title" />
+  <java-symbol type="string" name="throttle_warning_notification_message" />
+  <java-symbol type="string" name="throttle_warning_notification_title" />
+  <java-symbol type="string" name="throttled_notification_message" />
+  <java-symbol type="string" name="throttled_notification_title" />
+  <java-symbol type="string" name="usb_accessory_notification_title" />
+  <java-symbol type="string" name="usb_cd_installer_notification_title" />
+  <java-symbol type="string" name="usb_mtp_notification_title" />
+  <java-symbol type="string" name="usb_notification_message" />
+  <java-symbol type="string" name="usb_ptp_notification_title" />
+  <java-symbol type="string" name="vpn_text" />
+  <java-symbol type="string" name="vpn_text_long" />
+  <java-symbol type="string" name="vpn_title" />
+  <java-symbol type="string" name="vpn_title_long" />
+  <java-symbol type="string" name="wallpaper_binding_label" />
+  <java-symbol type="style" name="Theme.Dialog.AppError" />
+  <java-symbol type="style" name="Theme.Toast" />
+  <java-symbol type="xml" name="storage_list" />
+
+  <!-- From SystemUI -->
+  <java-symbol type="anim" name="push_down_in" />
+  <java-symbol type="anim" name="push_down_out" />
+  <java-symbol type="anim" name="push_up_in" />
+  <java-symbol type="anim" name="push_up_out" />
+  <java-symbol type="dimen" name="status_bar_icon_size" />
+  <java-symbol type="dimen" name="system_bar_icon_size" />
+  <java-symbol type="drawable" name="list_selector_pressed_holo_dark" />
+  <java-symbol type="drawable" name="scrubber_control_disabled_holo" />
+  <java-symbol type="drawable" name="scrubber_control_selector_holo" />
+  <java-symbol type="drawable" name="scrubber_progress_horizontal_holo_dark" />
+  <java-symbol type="drawable" name="usb_android" />
+  <java-symbol type="drawable" name="usb_android_connected" />
+  <java-symbol type="id" name="banner" />
+  <java-symbol type="id" name="mount_button" />
+  <java-symbol type="id" name="unmount_button" />
+  <java-symbol type="layout" name="usb_storage_activity" />
+  <java-symbol type="string" name="chooseUsbActivity" />
+  <java-symbol type="string" name="dlg_confirm_kill_storage_users_text" />
+  <java-symbol type="string" name="dlg_confirm_kill_storage_users_title" />
+  <java-symbol type="string" name="dlg_error_title" />
+  <java-symbol type="string" name="ext_media_badremoval_notification_message" />
+  <java-symbol type="string" name="ext_media_badremoval_notification_title" />
+  <java-symbol type="string" name="ext_media_checking_notification_message" />
+  <java-symbol type="string" name="ext_media_checking_notification_title" />
+  <java-symbol type="string" name="ext_media_nofs_notification_message" />
+  <java-symbol type="string" name="ext_media_nofs_notification_title" />
+  <java-symbol type="string" name="ext_media_nomedia_notification_message" />
+  <java-symbol type="string" name="ext_media_nomedia_notification_title" />
+  <java-symbol type="string" name="ext_media_safe_unmount_notification_message" />
+  <java-symbol type="string" name="ext_media_safe_unmount_notification_title" />
+  <java-symbol type="string" name="ext_media_unmountable_notification_message" />
+  <java-symbol type="string" name="ext_media_unmountable_notification_title" />
+  <java-symbol type="string" name="usb_storage_error_message" />
+  <java-symbol type="string" name="usb_storage_message" />
+  <java-symbol type="string" name="usb_storage_notification_message" />
+  <java-symbol type="string" name="usb_storage_notification_title" />
+  <java-symbol type="string" name="usb_storage_stop_message" />
+  <java-symbol type="string" name="usb_storage_stop_notification_message" />
+  <java-symbol type="string" name="usb_storage_stop_notification_title" />
+  <java-symbol type="string" name="usb_storage_stop_title" />
+  <java-symbol type="string" name="usb_storage_title" />
+
+  <!-- ImfTest -->
+  <java-symbol type="layout" name="auto_complete_list" />
+
+  <!-- From SettingsProvider -->
+  <java-symbol type="raw" name="fallbackring" />
+
+  <!-- From Settings -->
+  <java-symbol type="array" name="config_mobile_hotspot_provision_app" />
+  <java-symbol type="bool" name="config_intrusiveNotificationLed" />
+  <java-symbol type="dimen" name="preference_fragment_padding_bottom" />
+  <java-symbol type="dimen" name="preference_fragment_padding_side" />
+  <java-symbol type="drawable" name="expander_ic_maximized" />
+  <java-symbol type="drawable" name="expander_ic_minimized" />
+  <java-symbol type="drawable" name="ic_menu_archive" />
+  <java-symbol type="drawable" name="ic_menu_goto" />
+  <java-symbol type="drawable" name="title_bar_medium" />
+  <java-symbol type="id" name="body" />
+  <java-symbol type="string" name="fast_scroll_alphabet" />
+  <java-symbol type="string" name="ssl_certificate" />
+
+  <!-- From Phone -->
+  <java-symbol type="bool" name="config_built_in_sip_phone" />
+
+  <!-- From TelephonyProvider -->
+  <java-symbol type="xml" name="apns" />
+
+  <!-- From ContactsProvider -->
+  <java-symbol type="array" name="common_nicknames" />
+  <java-symbol type="drawable" name="call_contact" />
+  <java-symbol type="drawable" name="create_contact" />
+  <java-symbol type="string" name="common_name_prefixes" />
+  <java-symbol type="string" name="common_last_name_prefixes" />
+  <java-symbol type="string" name="common_name_suffixes" />
+  <java-symbol type="string" name="common_name_conjunctions" />
+  <java-symbol type="string" name="dial_number_using" />
+  <java-symbol type="string" name="create_contact_using" />
+
+  <!-- From DownloadProvider -->
+  <java-symbol type="integer" name="config_MaxConcurrentDownloadsAllowed" />
+  <java-symbol type="integer" name="config_downloadDataDirSize" />
+  <java-symbol type="integer" name="config_downloadDataDirLowSpaceThreshold" />
+
+  <!-- From Contacts -->
+  <java-symbol type="drawable" name="quickcontact_badge_overlay_dark" />
+
+  <!-- From Browser -->
+  <java-symbol type="drawable" name="ic_menu_moreoverflow_normal_holo_dark" />
+  <java-symbol type="id" name="placeholder" />
+  <java-symbol type="string" name="ssl_certificate_is_valid" />
+
+  <!-- From Mms -->
+  <java-symbol type="drawable" name="ic_menu_play_clip" />
+
+  <!-- From Stk -->
+  <java-symbol type="bool" name="config_sf_slowBlur" />
+  <java-symbol type="drawable" name="ic_volume" />
+  <java-symbol type="drawable" name="stat_notify_sim_toolkit" />
+
+  <!-- From PinyinIME(!!!) -->
+  <java-symbol type="string" name="inputMethod" />
+
   <!-- AndroidManifest.xml attributes. -->
   <eat-comment />
 
@@ -1974,4 +3490,12 @@
   <public type="color" name="holo_orange_dark" id="0x01060019" />
   <public type="color" name="holo_purple" id="0x0106001a" />
   <public type="color" name="holo_blue_bright" id="0x0106001b" />
+
+<!-- ===============================================================
+     Resources added in version 16 of the platform (Jelly Bean)
+     =============================================================== -->
+  <public type="attr" name="isolatedProcess" id="0x010103a7" />
+
+  <public type="attr" name="textDirection"/>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dc45c408..c95dddd 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -532,6 +532,13 @@
         tasks and kill their apps. Malicious apps may disrupt
         the behavior of other apps.</string>
 
+    <!-- Title of an application permission, allowing control of app screen compatibility mode -->
+    <string name="permlab_setScreenCompatibility">set screen compatibility</string>
+    <!-- Description of an application permission, allowing control of app screen compatibility mode -->
+    <string name="permdesc_setScreenCompatibility">Allows the app to control the
+        screen compatibility mode of other applications.  Malicious applications may
+        break the behavior of other applications.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setDebugApp">enable app debugging</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -2236,6 +2243,11 @@
     <string name="permdesc_bindPackageVerifier">Allows the holder to make requests of
         package verifiers. Should never be needed for normal apps.</string>
 
+    <!-- Title of an application permission which allows the application to access serial ports via the SerialManager. [CHAR LIMIT=40] -->
+    <string name="permlab_serialPort">access serial ports</string>
+    <!-- Description of an application permission which allows the application access serial ports via the SerialManager. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_serialPort">Allows the holder to access serial ports using the SerialManager API.</string>
+
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. -->
     <string name="save_password_message">Do you want the browser to remember this password?</string>
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. -->
@@ -2696,11 +2708,6 @@
     <!-- Do not translate. Default access point SSID used for tethering -->
     <string name="wifi_tether_configure_ssid_default" translatable="false">AndroidAP</string>
 
-    <!-- Wi-Fi p2p dialog title-->
-    <string name="wifi_p2p_dialog_title">Wi-Fi Direct</string>
-    <string name="wifi_p2p_turnon_message">Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot.</string>
-    <string name="wifi_p2p_failed_message">Couldn\'t start Wi-Fi Direct.</string>
-
     <string name="accept">Accept</string>
     <string name="decline">Decline</string>
     <string name="wifi_p2p_invitation_sent_title">Invitation sent</string>
@@ -2711,9 +2718,6 @@
     <string name="wifi_p2p_enter_pin_message">Type the required PIN: </string>
     <string name="wifi_p2p_show_pin_message">PIN: </string>
 
-    <string name="wifi_p2p_enabled_notification_title">Wi-Fi Direct is on</string>
-    <string name="wifi_p2p_enabled_notification_message">Touch for settings</string>
-
     <!-- Name of the dialog that lets the user choose an accented character to insert -->
     <string name="select_character">Insert character</string>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 3b6d6f1..610bad8 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -112,7 +112,7 @@
     </style>
 
     <!-- Standard animations for a translucent window or activity.  This
-         style is <em>not<em> used by default for the translucent theme
+         style is <em>not</em> used by default for the translucent theme
          (since translucent activities are a special case that have no
          clear UI paradigm), but you can make your own specialized theme
          with this animation style if you would like to have the standard
@@ -198,8 +198,10 @@
     <!-- A special animation we can use for recent applications,
          for devices that can support it (do alpha transformations). -->
     <style name="Animation.RecentApplications">
-        <item name="windowEnterAnimation">@anim/fade_in</item>
-        <item name="windowExitAnimation">@anim/fade_out</item>
+        <item name="windowEnterAnimation">@anim/recents_fade_in</item>
+        <item name="windowShowAnimation">@anim/recents_fade_in</item>
+        <item name="windowExitAnimation">@anim/recents_fade_out</item>
+        <item name="windowHideAnimation">@anim/recents_fade_out</item>
     </style>
 
     <!-- A special animation value used internally for popup windows. -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index fe5388b..7046fc5 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -29,15 +29,16 @@
 ===============================================================
  -->
 <resources>
-    <!-- The default system theme. This is the theme used for activities
-         that have not explicitly set their own theme.
-         
+    <!-- The default theme for apps on API level 10 and lower. This is the theme used for
+         activities that have not explicitly set their own theme.
          <p>You can count on this being a dark
          background with light text on top, but should try to make no
          other assumptions about its appearance. In particular, the text
          inside of widgets using this theme may be completely different,
          with the widget container being a light color and the text on top
          of it a dark color.
+         <p>If you're developing for API level 11 and higher, you should instead use {@link
+         #Theme_Holo} or {@link #Theme_DeviceDefault}.</p>
     -->
     <style name="Theme">
 
@@ -370,13 +371,12 @@
         <item name="pointerStyle">@android:style/Pointer</item>
     </style>
 
-    <!-- Variant of the default (dark) theme with no title bar -->
+    <!-- Variant of {@link #Theme} with no title bar -->
     <style name="Theme.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variant of the default (dark) theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme} that has no title bar and no status bar -->
     <style name="Theme.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
@@ -385,7 +385,8 @@
     <!-- Theme for a light background with dark text on top.  Set your activity
          to this theme if you would like such an appearance.  As with the
          default theme, you should try to assume little more than that the
-         background will be a light color. -->
+         background will be a light color.
+         <p>This is designed for API level 10 and lower.</p>-->
     <style name="Theme.Light">
         <item name="windowBackground">@android:drawable/screen_background_selector_light</item>
         <item name="colorBackground">@android:color/background_light</item>
@@ -457,19 +458,19 @@
         <item name="detailsElementBackground">@android:drawable/panel_bg_holo_light</item>
     </style>
 
-    <!-- Variant of the light theme with no title bar -->
+    <!-- Variant of {@link #Theme_Light} with no title bar -->
     <style name="Theme.Light.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variant of the light theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme_Light} that has no title bar and
+         no status bar -->
     <style name="Theme.Light.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
-    <!-- Special variation on the default theme that ensures the background is
+    <!-- Variant on {@link #Theme} that ensures the background is
          completely black.  This is useful for things like image viewers and
          media players.   If you want the normal (dark background) theme
          do <em>not</em> use this, use {@link #Theme}. -->
@@ -478,40 +479,40 @@
         <item name="android:colorBackground">@android:color/black</item>
     </style>
     
-    <!-- Variant of the black theme with no title bar -->
+    <!-- Variant of {@link #Theme_Black} with no title bar -->
     <style name="Theme.Black.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variant of the black theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme_Black} that has no title bar and
+         no status bar -->
     <style name="Theme.Black.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
     
-    <!-- Default theme for windows that want to have the user's selected
-         wallpaper appear behind them.  -->
+    <!-- Theme for windows that want to have the user's selected
+         wallpaper appear behind them (for API level 10 and lower).  -->
     <style name="Theme.Wallpaper">
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
         <item name="android:windowShowWallpaper">true</item>
     </style>
 
-    <!-- Variant of the translucent theme with no title bar -->
+    <!-- Variant of {@link #Theme_Wallpaper} that has no title bar -->
     <style name="Theme.Wallpaper.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variant of the translucent theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme_Wallpaper} that
+         has no title bar or status bar. -->
     <style name="Theme.Wallpaper.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
-    <!-- Theme for a wallpaper's setting activity that is designed to be on
-         top of a dark background. -->
+    <!-- Theme for a wallpaper's setting activity, which is designed to be a transparent
+         background with a dark shade, so the previous Activity is visible in the background. -->
     <style name="Theme.WallpaperSettings">
         <item name="android:windowBackground">@android:drawable/screen_background_dark_transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
@@ -519,8 +520,8 @@
         <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
     </style>
 
-    <!-- Theme for a wallpaper's setting activity that is designed to be on
-         top of a light background. -->
+    <!-- Theme for a wallpaper's setting activity, which is designed to be a transparent
+         background with a light shade, so the previous Activity is visible in the background. -->
     <style name="Theme.Light.WallpaperSettings">
         <item name="android:windowBackground">@android:drawable/screen_background_light_transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
@@ -538,8 +539,8 @@
     <style name="PreviewWallpaperSettings">
     </style>
     
-    <!-- Default theme for translucent activities, that is windows that allow you
-         to see through them to the windows behind.  This sets up the translucent
+    <!-- Theme for translucent activities (on API level 10 and lower). That is, windows
+         that allow you to see through them to the windows behind.  This sets up the translucent
          flag and appropriate animations for your windows.  -->
     <style name="Theme.Translucent">
         <item name="android:windowBackground">@android:color/transparent</item>
@@ -551,14 +552,14 @@
         <item name="android:windowAnimationStyle">@android:style/Animation</item>
     </style>
 
-    <!-- Variant of the translucent theme with no title bar -->
+    <!-- Variant of {@link #Theme_Translucent} with no title bar -->
     <style name="Theme.Translucent.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
-    <!-- Variant of the translucent theme that has no title bar and
-         fills the entire screen -->
+    <!-- Variant of {@link #Theme_Translucent} that has no title bar and
+         no status bar -->
     <style name="Theme.Translucent.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
     </style>
@@ -574,7 +575,8 @@
         <item name="android:windowNoDisplay">true</item>
     </style>
 
-    <!-- Default theme for dialog windows and activities, which is used by the
+    <!-- Default theme for dialog windows and activities (on API level 10 and lower),
+         which is used by the
          {@link android.app.Dialog} class.  This changes the window to be
          floating (not fill the entire screen), and puts a frame around its
          contents.  You can set this theme on an activity if you would like to
@@ -622,7 +624,7 @@
         <item name="listPreferredItemPaddingRight">10dip</item>
     </style>
 
-    <!-- Variation of Theme.Dialog that does not include a frame (or background).
+    <!-- Variant of {@link Theme_Dialog} that does not include a frame (or background).
          The view hierarchy of the dialog is responsible for drawing all of
          its pixels. -->
     <style name="Theme.Dialog.NoFrame">
@@ -636,7 +638,7 @@
         <item name="android:windowCloseOnTouchOutside">false</item>
     </style>
 
-    <!-- Default theme for alert dialog windows, which is used by the
+    <!-- Default theme for alert dialog windows (on API level 10 and lower), which is used by the
          {@link android.app.AlertDialog} class.  This is basically a dialog
          but sets the background to empty so it can do two-tone backgrounds. -->
     <style name="Theme.Dialog.Alert">
@@ -648,8 +650,8 @@
         <item name="textAppearanceListItemSmall">@android:style/TextAppearance.Large.Inverse</item>
     </style>
     
-    <!-- Default dark theme for panel windows.  This removes all extraneous
-         window decorations, so you basically have an empty rectangle in which
+    <!-- Default dark theme for panel windows (on API level 10 and lower).  This removes all
+         extraneous window decorations, so you basically have an empty rectangle in which
          to place your content.  It makes the window floating, with a transparent
          background, and turns off dimming behind the window. -->
     <style name="Theme.Panel">
@@ -664,8 +666,8 @@
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Default light theme for panel windows.  This removes all extraneous
-         window decorations, so you basically have an empty rectangle in which
+    <!-- Default light theme for panel windows (on API level 10 and lower).  This removes all
+         extraneous window decorations, so you basically have an empty rectangle in which
          to place your content.  It makes the window floating, with a transparent
          background, and turns off dimming behind the window. -->
     <style name="Theme.Light.Panel">
@@ -712,7 +714,7 @@
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Default theme for input methods, which is used by the
+    <!-- Default theme for input methods (on API level 10 and lower), which is used by the
          {@link android.inputmethodservice.InputMethodService} class.
          this inherits from Theme.Panel, but sets up IME appropriate animations
          and a few custom attributes. -->
@@ -723,7 +725,7 @@
         <item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
     </style>
 
-    <!-- Default theme for modern holo style input methods, which is used by the
+    <!-- Default theme for holo style input methods, which is used by the
          {@link android.inputmethodservice.InputMethodService} class.
          this inherits from Theme.Panel, but sets up IME appropriate animations
          and a few custom attributes. -->
@@ -842,14 +844,23 @@
         <item name="android:windowActionModeOverlay">true</item>
     </style>
     
-    <!-- New Honeycomb holographic theme. Dark version.  The widgets in the
-         holographic theme are translucent on their brackground, so applications
-         must ensure that any background they use with this theme is itself
-         dark; otherwise, it will be difficult to see the widgets.  The new
-         UI style also includes a full action bar by default.
+    <!-- Honeycomb holographic theme (dark version).
+         <p>This is the default system theme for apps that target API level 11 - 13. Starting
+         with API level 14, the default system theme is supplied by {@link #Theme_DeviceDefault},
+         which might apply a different style on different devices. If you want to ensure that your
+         app consistenly uses the Holo theme at all times, you must explicitly declare it in your
+         manifest. For example, {@code &lt;application android:theme="@android:style/Theme.Holo"&gt;}.
+         For more information, read <a
+         href="http://android-developers.blogspot.com/2012/01/holo-everywhere.html">Holo
+         Everywhere</a>.</p>
+         <p>The widgets in the holographic theme are translucent on their brackground, so
+         applications must ensure that any background they use with this theme is itself
+         dark; otherwise, it will be difficult to see the widgets. This UI style also includes a
+         full action bar by default.</p>
 
-         Styles used by the Holo theme are named using the convention Type.Holo.Etc.
-         (For example, Widget.Holo.Button, TextAppearance.Holo.Widget.PopupMenu.Large.)
+         <p>Styles used by the Holo theme are named using the convention Type.Holo.Etc
+         (for example, {@code Widget.Holo.Button} and {@code
+         TextAppearance.Holo.Widget.PopupMenu.Large}).
          Specific resources used by Holo are named using the convention @type/foo_bar_baz_holo
          with trailing _dark or _light specifiers if they are not shared between both light and
          dark versions of the theme. -->
@@ -951,15 +962,12 @@
         <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_dark</item>
 
         <item name="expandableListPreferredItemPaddingLeft">40dip</item>
-        <item name="expandableListPreferredChildPaddingLeft">
-                ?android:attr/expandableListPreferredItemPaddingLeft</item>
+        <item name="expandableListPreferredChildPaddingLeft">?android:attr/expandableListPreferredItemPaddingLeft</item>
 
         <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
         <item name="expandableListPreferredItemIndicatorRight">0dip</item>
-        <item name="expandableListPreferredChildIndicatorLeft">
-                ?android:attr/expandableListPreferredItemIndicatorLeft</item>
-        <item name="expandableListPreferredChildIndicatorRight">
-                ?android:attr/expandableListPreferredItemIndicatorRight</item>
+        <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
+        <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
 
         <!-- Gallery attributes -->
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
@@ -1156,10 +1164,10 @@
 
     </style>
 
-    <!-- New Honeycomb holographic theme. Light version.  The widgets in the
+    <!-- Honeycomb holographic theme (light version).  The widgets in the
          holographic theme are translucent on their brackground, so applications
          must ensure that any background they use with this theme is itself
-         light; otherwise, it will be difficult to see the widgets.  The new
+         light; otherwise, it will be difficult to see the widgets.  This
          UI style also includes a full action bar by default. -->
     <style name="Theme.Holo.Light" parent="Theme.Light">
         <item name="colorForeground">@android:color/bright_foreground_holo_light</item>
@@ -1257,15 +1265,12 @@
         <item name="activatedBackgroundIndicator">@android:drawable/activated_background_holo_light</item>
 
         <item name="expandableListPreferredItemPaddingLeft">40dip</item>
-        <item name="expandableListPreferredChildPaddingLeft">
-                ?android:attr/expandableListPreferredItemPaddingLeft</item>
+        <item name="expandableListPreferredChildPaddingLeft">?android:attr/expandableListPreferredItemPaddingLeft</item>
 
         <item name="expandableListPreferredItemIndicatorLeft">3dip</item>
         <item name="expandableListPreferredItemIndicatorRight">0dip</item>
-        <item name="expandableListPreferredChildIndicatorLeft">
-                ?android:attr/expandableListPreferredItemIndicatorLeft</item>
-        <item name="expandableListPreferredChildIndicatorRight">
-                ?android:attr/expandableListPreferredItemIndicatorRight</item>
+        <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
+        <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
 
         <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_light</item>
 
@@ -1522,6 +1527,7 @@
     </style>
  
     <!-- Dialog themes for Holo -->
+    <eat-comment />
 
     <!-- Holo theme for dialog windows and activities, which is used by the
          {@link android.app.Dialog} class.  This changes the window to be
@@ -1554,27 +1560,27 @@
         <item name="listPreferredItemPaddingRight">16dip</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Dialog that has a nice minumum width for
+    <!-- Variant of Theme.Holo.Dialog that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Holo.Dialog.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Dialog that does not include a title bar. -->
+    <!-- Variant of Theme.Holo.Dialog that does not include a title bar. -->
     <style name="Theme.Holo.Dialog.NoActionBar">
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Dialog.NoActionVar that has a nice minumum width for
+    <!-- Variant of Theme.Holo.Dialog.NoActionBar that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Holo.Dialog.NoActionBar.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Dialog that does not include a frame (or background).
+    <!-- Variant of Theme.Holo.Dialog that does not include a frame (or background).
          The view hierarchy of the dialog is responsible for drawing all of
          its pixels. -->
     <style name="Theme.Holo.Dialog.NoFrame">
@@ -1646,20 +1652,20 @@
         <item name="listPreferredItemPaddingRight">16dip</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Light.Dialog that has a nice minumum width for
+    <!-- Variant of Theme.Holo.Light.Dialog that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Holo.Light.Dialog.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Light.Dialog that does not include a title bar. -->
+    <!-- Variant of Theme.Holo.Light.Dialog that does not include a title bar. -->
     <style name="Theme.Holo.Light.Dialog.NoActionBar">
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
     </style>
 
-    <!-- Variation of Theme.Holo.Light.Dialog.NoActionBar that has a nice minumum width for
+    <!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a nice minimum width for
          a regular dialog. -->
     <style name="Theme.Holo.Light.Dialog.NoActionBar.MinWidth">
         <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
@@ -1700,7 +1706,8 @@
         <item name="android:windowShowWallpaper">true</item>
     </style>
 
-    <!-- Variant of the holographic (dark) theme with no title bar -->
+    <!--Default holographic (dark) for windows that want to have the user's selected
+         wallpaper appear behind them and without an action bar. -->
     <style name="Theme.Holo.Wallpaper.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 8135986..abe4aad 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -31,6 +31,24 @@
 ===============================================================
  -->
 <resources>
+
+    <!-- The default theme for apps that target API level 14 and higher.
+         <p>The DeviceDefault themes are aliases for a specific device’s native look and feel. The
+         DeviceDefault theme family and widget style family offer ways for you to target your app
+         to a device’s native theme with all device customizations intact.</p>
+         <p>For example, when you set your app's {@code targetSdkVersion} to 14 or higher, this
+         theme is applied to your application by default. As such, your app might appear with the
+         {@link #Theme_Holo Holo} styles on one device, but with a different set of styles on
+         another device. This is great if you want your app to fit with the device's native look and
+         feel. If, however, you prefer to keep your UI style the same across all devices, you should
+         apply a specific theme such as {@link #Theme_Holo Holo} or one of your own design. For more
+         information, read <a
+         href="http://android-developers.blogspot.com/2012/01/holo-everywhere.html">Holo
+         Everywhere</a>.</p>
+         <p>Styles used by the DeviceDefault theme are named using the convention
+         Type.DeviceDefault.Etc (for example, {@code Widget.DeviceDefault.Button} and
+         {@code TextAppearance.DeviceDefault.Widget.PopupMenu.Large}).</p>
+          -->
     <style name="Theme.DeviceDefault" parent="Theme.Holo" >
         <!-- Text styles -->
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
@@ -176,12 +194,16 @@
         <!-- DatePicker style -->
         <item name="datePickerStyle">@style/Widget.DeviceDefault.DatePicker</item>
     </style>
+
+    <!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
     <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Holo.NoActionBar" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar -->
     <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Holo.NoActionBar.Fullscreen" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
     <style name="Theme.DeviceDefault.Light" parent="Theme.Holo.Light" >
         <!-- Text styles -->
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
@@ -322,12 +344,17 @@
         <!-- DatePicker style -->
         <item name="datePickerStyle">@style/Widget.DeviceDefault.Light.DatePicker</item>
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
     <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar -->
     <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Holo.Light.NoActionBar.Fullscreen" >
 
     </style>
+    <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
+    floating (not fill the entire screen), and puts a frame around its contents. You can set this
+    theme on an activity if you would like to make an activity that looks like a Dialog. -->
     <style name="Theme.DeviceDefault.Dialog" parent="Theme.Holo.Dialog" >
         <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
@@ -338,15 +365,23 @@
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
+    regular dialog. -->
     <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Holo.Dialog.MinWidth" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
     <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Holo.Dialog.NoActionBar" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
+    for a regular dialog. -->
     <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Dialog.NoActionBar.MinWidth" >
 
     </style>
+    <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
+    floating (not fill the entire screen), and puts a frame around its contents. You can set this
+    theme on an activity if you would like to make an activity that looks like a Dialog.-->
     <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Holo.Light.Dialog" >
         <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
@@ -357,42 +392,71 @@
         <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
         <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
+    regular dialog. -->
     <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Holo.Light.Dialog.MinWidth" >
 
     </style>
+     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
     <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Holo.Light.Dialog.NoActionBar" >
 
     </style>
+    <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
+    width for a regular dialog. -->
     <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Light.Dialog.NoActionBar.MinWidth" >
 
     </style>
+    <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
+    screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
     <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Holo.DialogWhenLarge" >
 
     </style>
+    <!-- DeviceDefault theme for a window without an action bar that will be displayed either
+    full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+    xlarge). -->
     <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Holo.DialogWhenLarge.NoActionBar" >
 
     </style>
+    <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
+    screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
     <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Holo.Light.DialogWhenLarge" >
 
     </style>
+    <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
+    full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+    xlarge). -->
     <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Holo.Light.DialogWhenLarge.NoActionBar" >
 
     </style>
+    <!-- DeviceDefault theme for panel windows. This removes all extraneous window
+    decorations, so you basically have an empty rectangle in which to place your content. It makes
+    the window floating, with a transparent background, and turns off dimming behind the window. -->
     <style name="Theme.DeviceDefault.Panel" parent="Theme.Holo.Panel" >
 
     </style>
+    <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
+    decorations, so you basically have an empty rectangle in which to place your content. It makes
+    the window floating, with a transparent background, and turns off dimming behind the window. -->
     <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Holo.Light.Panel" >
 
     </style>
+    <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+    behind them. -->
     <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Holo.Wallpaper" >
 
     </style>
+    <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+    behind them and without an action bar. -->
     <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Holo.Wallpaper.NoTitleBar" >
 
     </style>
+    <!-- DeviceDefault style for input methods, which is used by the
+         {@link android.inputmethodservice.InputMethodService} class.-->
     <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Holo.InputMethod" >
 
     </style>
+    <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
+    inverse color profile. -->
     <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Holo.Light.DarkActionBar" >
         <item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item>
 
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index 3ffa085..7233e7f 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -46,7 +46,7 @@
     @Override
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
-        if (!UtilHelper.isWifiOnly()) {
+        if (!UtilHelper.isWifiOnly(getContext())) {
             suite.addTestSuite(WifiApStress.class);
             suite.addTestSuite(WifiStressTest.class);
         } else {
@@ -64,7 +64,7 @@
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
-        if (!UtilHelper.isWifiOnly()) {
+        if (!UtilHelper.isWifiOnly(getContext())) {
             String valueStr = (String) icicle.get("softap_iterations");
             if (valueStr != null) {
                 int iteration = Integer.parseInt(valueStr);
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
index 20aae47..9819c54 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
@@ -40,7 +40,7 @@
     @Override
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
-        if (!UtilHelper.isWifiOnly()) {
+        if (!UtilHelper.isWifiOnly(getContext())) {
             suite.addTestSuite(ConnectivityManagerMobileTest.class);
         } else {
             // create a new test suite
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
index 1b966bf..b9fe6ed 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
@@ -16,12 +16,31 @@
 
 package com.android.connectivitymanagertest;
 
-import android.os.SystemProperties;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.util.Log;
 
 public class UtilHelper {
-    public static boolean isWifiOnly() {
-        return "wifi-only".equals(SystemProperties.get("ro.carrier"));
+
+    private static Boolean mIsWifiOnly = null;
+    private static final Object sLock = new Object();
+
+    /**
+     * Return true if device is a wifi only device.
+     */
+    public static boolean isWifiOnly(Context context) {
+        synchronized (sLock) {
+            // cache the result from pkgMgr statically. It will never change, since its a
+            // device configuration setting
+            if (mIsWifiOnly == null) {
+                PackageManager pkgMgr = context.getPackageManager();
+                mIsWifiOnly = Boolean.valueOf(!pkgMgr
+                        .hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+                        && pkgMgr.hasSystemFeature(PackageManager.FEATURE_WIFI));
+                String deviceType = mIsWifiOnly ? "wifi-only" : "telephony";
+                Log.d("ConnectivityManagerTest", String.format("detected a %s device", deviceType));
+            }
+        }
+        return mIsWifiOnly;
     }
-
-
 }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index b1f4bf1..52326d5 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -16,37 +16,31 @@
 
 package com.android.connectivitymanagertest.functional;
 
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
-import com.android.connectivitymanagertest.UtilHelper;
-
-import android.content.Intent;
 import android.content.Context;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.State;
-import android.net.NetworkInfo.DetailedState;
 import android.net.wifi.WifiManager;
-
-import android.test.suitebuilder.annotation.LargeTest;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
-import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
-import com.android.connectivitymanagertest.NetworkState;
+import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
-public class ConnectivityManagerMobileTest
-    extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
+import com.android.connectivitymanagertest.NetworkState;
+import com.android.connectivitymanagertest.UtilHelper;
+
+public class ConnectivityManagerMobileTest extends
+        ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
     private static final String LOG_TAG = "ConnectivityManagerMobileTest";
-    private static final String PKG_NAME = "com.android.connectivitymanagertest";
 
     private String TEST_ACCESS_POINT;
     private ConnectivityManagerTestActivity cmActivity;
     private WakeLock wl;
+    private boolean mIsWifiOnlyDevice;
 
     public ConnectivityManagerMobileTest() {
         super(ConnectivityManagerTestActivity.class);
@@ -69,7 +63,8 @@
             log("airplane is not disabled, disable it.");
             cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
         }
-        if (!UtilHelper.isWifiOnly()) {
+        mIsWifiOnlyDevice = UtilHelper.isWifiOnly(mRunner.getTargetContext());
+        if (!mIsWifiOnlyDevice) {
             if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
                     ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
                 // Note: When the test fails in setUp(), tearDown is not called. In that case,
@@ -166,7 +161,7 @@
     public void testConnectToWifi() {
         assertNotNull("SSID is null", TEST_ACCESS_POINT);
         NetworkInfo networkInfo;
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             //Prepare for connectivity verification
             networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
             cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
@@ -185,7 +180,7 @@
         log("wifi state is enabled");
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
@@ -197,7 +192,7 @@
                     cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
                 log("Mobile state transition validation failed.");
                 log("reason: " +
@@ -232,13 +227,13 @@
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
                 State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
 
         NetworkInfo networkInfo;
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             //Prepare for connectivity state verification
             networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
             cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
@@ -258,7 +253,7 @@
         // Wait for Wifi to be connected and mobile to be disconnected
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
@@ -288,7 +283,7 @@
         sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
 
         NetworkInfo networkInfo;
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
             cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
                                                   networkInfo.getState(),
@@ -304,7 +299,7 @@
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                 ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
@@ -316,7 +311,7 @@
                     cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue(false);
         }
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
                 log("Mobile state transition validation failed.");
                 log("reason: " +
@@ -393,7 +388,7 @@
         cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
 
         NetworkInfo networkInfo;
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
             networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
@@ -419,7 +414,7 @@
                     cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
             assertTrue("State validation failed", false);
         }
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
                 log("state validation for Mobile failed");
                 log("reason: " +
@@ -471,7 +466,7 @@
 
         assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
                             ConnectivityManagerTestActivity.LONG_TIMEOUT));
-        if (!UtilHelper.isWifiOnly()) {
+        if (!mIsWifiOnlyDevice) {
             assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                     State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
         }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 2069789..feb63cd 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -16,10 +16,6 @@
 
 package com.android.connectivitymanagertest.stress;
 
-import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
-import com.android.connectivitymanagertest.UtilHelper;
-
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo.State;
@@ -31,15 +27,15 @@
 import android.net.wifi.WifiManager;
 import android.os.Environment;
 import android.os.PowerManager;
-import android.os.IPowerManager;
-import android.os.SystemClock;
-import android.os.ServiceManager;
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
-
 import android.util.Log;
 
+import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
+import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.UtilHelper;
+
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileWriter;
@@ -79,6 +75,7 @@
     private String mPassword;
     private ConnectivityManagerStressTestRunner mRunner;
     private BufferedWriter mOutputWriter = null;
+    private boolean mIsWifiOnlyDevice;
 
     public WifiStressTest() {
         super(ConnectivityManagerTestActivity.class);
@@ -100,6 +97,7 @@
         mOutputWriter = new BufferedWriter(new FileWriter(new File(
                 Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
         mAct.turnScreenOn();
+        mIsWifiOnlyDevice = UtilHelper.isWifiOnly(mRunner.getTargetContext());
         if (!mAct.mWifiManager.isWifiEnabled()) {
             log("Enable wi-fi before stress tests.");
             if (!mAct.enableWifi()) {
@@ -271,7 +269,7 @@
             assertTrue("Wait for Wi-Fi to idle timeout",
                     mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
                     6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
-            if (!UtilHelper.isWifiOnly()) {
+            if (!mIsWifiOnlyDevice) {
                 // use long timeout as the pppd startup may take several retries.
                 assertTrue("Wait for cellular connection timeout",
                         mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
@@ -282,7 +280,7 @@
             assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
                     mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
 
-            if (!UtilHelper.isWifiOnly()) {
+            if (!mIsWifiOnlyDevice) {
                 assertEquals("Cellular connection is down", State.CONNECTED,
                              mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
                 assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index a781472..76b702e 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -90,6 +90,7 @@
      */
     @LargeTest
     public void testWifiDownload() throws Exception {
+        mConnectionUtil.wifiTestInit();
         assertTrue("Could not connect to wifi!", setDeviceWifiAndAirplaneMode(mSsid));
         downloadFile();
     }
@@ -143,6 +144,7 @@
      */
     @LargeTest
     public void testWifiUpload() throws Exception {
+        mConnectionUtil.wifiTestInit();
         assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
         uploadFile();
     }
@@ -197,6 +199,7 @@
      */
     @LargeTest
     public void testWifiDownloadWithDownloadManager() throws Exception {
+        mConnectionUtil.wifiTestInit();
         assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
         downloadFileUsingDownloadManager();
     }
@@ -286,6 +289,8 @@
      * @return true if we successfully connect to mobile data.
      */
     public boolean hasMobileData() {
+        assertTrue(mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+                State.CONNECTED, ConnectionUtil.LONG_TIMEOUT));
         assertTrue("Not connected to mobile", mConnectionUtil.isConnectedToMobile());
         assertFalse("Still connected to wifi.", mConnectionUtil.isConnectedToWifi());
         return mConnectionUtil.hasData();
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index a5e5ab0e..7499f68 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -57,7 +57,7 @@
     private static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; // 10 seconds
     private static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
     public static final int SHORT_TIMEOUT = 5 * 1000;
-    public static final int LONG_TIMEOUT = 10 * 1000;
+    public static final int LONG_TIMEOUT = 120 * 1000; // 2 minutes
     private ConnectivityReceiver mConnectivityReceiver = null;
     private WifiReceiver mWifiReceiver = null;
     private DownloadReceiver mDownloadReceiver = null;
@@ -118,8 +118,14 @@
 
         initializeNetworkStates();
 
-        mWifiManager.setWifiEnabled(true);
 
+    }
+
+    /**
+     * Additional initialization needed for wifi related tests.
+     */
+    public void wifiTestInit() {
+        mWifiManager.setWifiEnabled(true);
         Log.v(LOG_TAG, "Clear Wifi before we start the test.");
         sleep(SHORT_TIMEOUT);
         removeConfiguredNetworksAndDisableWifi();
@@ -146,10 +152,10 @@
                 Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
                 return;
             }
-            if (intent.hasExtra(ConnectivityManager.EXTRA_NETWORK_INFO)) {
-                mNetworkInfo = (NetworkInfo)
-                        intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
-            }
+
+            final ConnectivityManager connManager = (ConnectivityManager) context
+                    .getSystemService(Context.CONNECTIVITY_SERVICE);
+            mNetworkInfo = connManager.getActiveNetworkInfo();
 
             if (intent.hasExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO)) {
                 mOtherNetworkInfo = (NetworkInfo)
@@ -525,7 +531,7 @@
     /**
      * Connect to Wi-Fi with the given configuration.
      * @param config
-     * @return true if we ar connected to a given
+     * @return true if we are connected to a given AP.
      */
     public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
         //  The SSID in the configuration is a pure string, need to convert it to a quoted string.
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
index b4a0581..a9f144b 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
@@ -14,12 +14,12 @@
 
 package android.accessibilityservice;
 
-import com.android.frameworks.coretests.R;
-
 import android.app.Activity;
 import android.os.Bundle;
 import android.view.View;
 
+import com.android.frameworks.coretests.R;
+
 /**
  * Activity for testing the accessibility APIs for "interrogation" of
  * the screen content. These APIs allow exploring the screen and
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
index 259a094..2fb4237 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
@@ -14,26 +14,21 @@
 
 package android.accessibilityservice;
 
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
 
-import android.content.Context;
 import android.graphics.Rect;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
-import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityInteractionClient;
-import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.IAccessibilityManager;
 
 import com.android.frameworks.coretests.R;
+import com.android.internal.util.Predicate;
 
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -48,21 +43,15 @@
  */
 public class InterrogationActivityTest
         extends ActivityInstrumentationTestCase2<InterrogationActivity> {
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static String LOG_TAG = "InterrogationActivityTest";
 
-    // Timeout before give up wait for the system to process an accessibility setting change.       
-    private static final int TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING = 2000;
-
     // Timeout for the accessibility state of an Activity to be fully initialized.
-    private static final int TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS = 100;
+    private static final int TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS = 5000;
 
     // Handle to a connection to the AccessibilityManagerService
-    private static int sConnectionId = View.NO_ID;
-
-    // The last received accessibility event
-    private volatile AccessibilityEvent mLastAccessibilityEvent;
+    private UiTestAutomationBridge mUiTestAutomationBridge;
 
     public InterrogationActivityTest() {
         super(InterrogationActivity.class);
@@ -70,16 +59,39 @@
 
     @Override
     public void setUp() throws Exception {
-        ensureConnection();
-        bringUpActivityWithInitalizedAccessbility();
+        super.setUp();
+        mUiTestAutomationBridge = new UiTestAutomationBridge();
+        mUiTestAutomationBridge.connect();
+        mUiTestAutomationBridge.executeCommandAndWaitForAccessibilityEvent(new Runnable() {
+                // wait for the first accessibility event
+                @Override
+                public void run() {
+                    // bring up the activity
+                    getActivity();
+                }
+            },
+            new Predicate<AccessibilityEvent>() {
+                @Override
+                public boolean apply(AccessibilityEvent event) {
+                    return (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+                            && event.getPackageName().equals(getActivity().getPackageName()));
+                }
+            },
+            TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mUiTestAutomationBridge.disconnect();
+        super.tearDown();
     }
 
     @LargeTest
     public void testFindAccessibilityNodeInfoByViewId() throws Exception {
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertNotNull(button);
             assertEquals(0, button.getChildCount());
 
@@ -125,8 +137,8 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view by text
-            List<AccessibilityNodeInfo> buttons =  AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfosByTextInActiveWindow(sConnectionId, "butto");
+            List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
+                .findAccessibilityNodeInfosByTextInActiveWindow("butto");
             assertEquals(9, buttons.size());
         } finally {
             if (DEBUG) {
@@ -141,12 +153,9 @@
     public void testFindAccessibilityNodeInfoByViewTextContentDescription() throws Exception {
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
-            bringUpActivityWithInitalizedAccessbility();
-
             // find a view by text
-            List<AccessibilityNodeInfo> buttons =  AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfosByTextInActiveWindow(sConnectionId,
-                        "contentDescription");
+            List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
+                .findAccessibilityNodeInfosByTextInActiveWindow("contentDescription");
             assertEquals(1, buttons.size());
         } finally {
             if (DEBUG) {
@@ -177,8 +186,8 @@
             classNameAndTextList.add("android.widget.ButtonButton8");
             classNameAndTextList.add("android.widget.ButtonButton9");
 
-            AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.root);
+            AccessibilityNodeInfo root = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
             assertNotNull("We must find the existing root.", root);
 
             Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
@@ -216,16 +225,16 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isFocused());
 
             // focus the view
             assertTrue(button.performAction(ACTION_FOCUS));
 
             // find the view again and make sure it is focused
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                    .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isFocused());
         } finally {
             if (DEBUG) {
@@ -240,24 +249,24 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isFocused());
 
             // focus the view
             assertTrue(button.performAction(ACTION_FOCUS));
 
             // find the view again and make sure it is focused
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isFocused());
 
             // unfocus the view
             assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
 
             // find the view again and make sure it is not focused
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isFocused());
         } finally {
             if (DEBUG) {
@@ -273,16 +282,16 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not selected
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
 
             // select the view
             assertTrue(button.performAction(ACTION_SELECT));
 
             // find the view again and make sure it is selected
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isSelected());
         } finally {
             if (DEBUG) {
@@ -297,24 +306,24 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not selected
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
 
             // select the view
             assertTrue(button.performAction(ACTION_SELECT));
 
             // find the view again and make sure it is selected
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertTrue(button.isSelected());
 
             // unselect the view
             assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
 
             // find the view again and make sure it is not selected
-            button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
             assertFalse(button.isSelected());
         } finally {
             if (DEBUG) {
@@ -330,23 +339,33 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
-            assertFalse(button.isSelected());
+            final AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
+            assertFalse(button.isFocused());
 
-            // focus the view
-            assertTrue(button.performAction(ACTION_FOCUS));
-
-            synchronized (this) {
-                try {
-                    wait(TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS);
-                } catch (InterruptedException ie) {
-                    /* ignore */
+            AccessibilityEvent event = mUiTestAutomationBridge
+                    .executeCommandAndWaitForAccessibilityEvent(new Runnable() {
+                @Override
+                public void run() {
+                    // focus the view
+                    assertTrue(button.performAction(ACTION_FOCUS));
                 }
-            }
+            },
+            new Predicate<AccessibilityEvent>() {
+                @Override
+                public boolean apply(AccessibilityEvent event) {
+                    return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED
+                            && event.getPackageName().equals(getActivity().getPackageName())
+                            && event.getText().get(0).equals(button.getText()));
+                }
+            },
+            TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
+
+            // check the last event
+            assertNotNull(event);
 
             // check that last event source
-            AccessibilityNodeInfo source = mLastAccessibilityEvent.getSource();
+            AccessibilityNodeInfo source = event.getSource();
             assertNotNull(source);
 
             // bounds
@@ -389,8 +408,9 @@
         final long startTimeMillis = SystemClock.uptimeMillis();
         try {
             // find a view and make sure it is not focused
-            AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
-                .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+            AccessibilityNodeInfo button = mUiTestAutomationBridge
+                .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
+            assertNotNull(button);
             AccessibilityNodeInfo parent = button.getParent();
             final int childCount = parent.getChildCount();
             for (int i = 0; i < childCount; i++) {
@@ -411,69 +431,33 @@
         }
     }
 
-    private void bringUpActivityWithInitalizedAccessbility() {
-        mLastAccessibilityEvent = null;
-        // bring up the activity
-        getActivity();
-
+    @LargeTest
+    public void testGetRootAccessibilityNodeInfoInActiveWindow() throws Exception {
         final long startTimeMillis = SystemClock.uptimeMillis();
-        while (true) {
-            if (mLastAccessibilityEvent != null) {
-                final int eventType = mLastAccessibilityEvent.getEventType();
-                if (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
-                    return;
+        try {
+            // get the root via the designated API
+            AccessibilityNodeInfo fetched = mUiTestAutomationBridge
+                    .getRootAccessibilityNodeInfoInActiveWindow();
+            assertNotNull(fetched);
+
+            // get the root via traversal
+            AccessibilityNodeInfo expected = mUiTestAutomationBridge
+                    .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
+            while (true) {
+                AccessibilityNodeInfo parent = expected.getParent();
+                if (parent == null) {
+                    break;
                 }
+                expected = parent;
             }
-            final long remainingTimeMillis = TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS
-                    - (SystemClock.uptimeMillis() - startTimeMillis);
-            if (remainingTimeMillis <= 0) {
-                return;
-            }
-            synchronized (this) {
-                try {
-                    wait(remainingTimeMillis);
-                } catch (InterruptedException e) {
-                    /* ignore */
-                }
-            }
-        }
-    }
+            assertNotNull(expected);
 
-    private void ensureConnection() throws Exception {
-        if (sConnectionId == View.NO_ID) {
-            IEventListener listener = new IEventListener.Stub() {
-                public void setConnection(IAccessibilityServiceConnection connection,
-                        int connectionId) {
-                    sConnectionId = connectionId;
-                    if (connection != null) {
-                        AccessibilityInteractionClient.getInstance().addConnection(connectionId,
-                                connection);
-                    } else {
-                        AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
-                    }
-                    synchronized (this) {
-                        notifyAll();
-                    }
-                }
-
-                public void onInterrupt() {}
-
-                public void onAccessibilityEvent(AccessibilityEvent event) {
-                    mLastAccessibilityEvent = AccessibilityEvent.obtain(event);
-                    synchronized (this) {
-                        notifyAll();
-                    }
-                }
-            };
-
-            AccessibilityManager accessibilityManager =
-                AccessibilityManager.getInstance(getInstrumentation().getContext());
-
-            synchronized (this) {
-                IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
-                        ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
-                manager.registerEventListener(listener);
-                wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING);
+            assertEquals("The node with id \"root\" should be the root.", expected, fetched);
+        } finally {
+            if (DEBUG) {
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                Log.i(LOG_TAG, "testGetRootAccessibilityNodeInfoInActiveWindow: "
+                        + elapsedTimeMillis + "ms");
             }
         }
     }
diff --git a/core/tests/coretests/src/android/app/activity/BroadcastTest.java b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
index 4b1f9fd..d527c0d 100644
--- a/core/tests/coretests/src/android/app/activity/BroadcastTest.java
+++ b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
@@ -303,7 +303,8 @@
     public void testSetSticky() throws Exception {
         Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
         intent.putExtra("test", LaunchpadActivity.DATA_1);
-        ActivityManagerNative.getDefault().unbroadcastIntent(null, intent);
+        ActivityManagerNative.getDefault().unbroadcastIntent(null, intent,
+                Binder.getOrigCallingUser());
 
         ActivityManagerNative.broadcastStickyIntent(intent, null);
         addIntermediate("finished-broadcast");
@@ -320,7 +321,8 @@
         ActivityManagerNative.broadcastStickyIntent(intent, null);
 
         ActivityManagerNative.getDefault().unbroadcastIntent(
-                null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null));
+                null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null),
+                Binder.getOrigCallingUser());
         addIntermediate("finished-unbroadcast");
 
         IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index 1df763a..b181122 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -24,6 +24,8 @@
 import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
 import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
 import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
+import static android.net.TrafficStats.GB_IN_BYTES;
+import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -50,10 +52,6 @@
 
     private static final long TEST_START = 1194220800000L;
 
-    private static final long KB_IN_BYTES = 1024;
-    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
-    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
-
     private NetworkStatsHistory stats;
 
     @Override
diff --git a/data/etc/android.hardware.bluetooth.xml b/data/etc/android.hardware.bluetooth.xml
new file mode 100644
index 0000000..4aa1744
--- /dev/null
+++ b/data/etc/android.hardware.bluetooth.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Adds the feature indicating support for the Bluetooth API -->
+<permissions>
+    <feature name="android.hardware.bluetooth" />
+</permissions>
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 02d2f3d..ef38a60 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -51,6 +51,11 @@
     $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(font_symlink)
 
 ################################
+# On space-constrained devices, we include a subset of fonts:
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+droidsans_fallback_src := DroidSansFallback.ttf
+extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf
+else
 include $(CLEAR_VARS)
 LOCAL_MODULE := DroidSansEthiopic-Regular.ttf
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
@@ -59,15 +64,11 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
 include $(BUILD_PREBUILT)
 
-################################
-ifeq ($(SMALLER_FONT_FOOTPRINT),true)
-droidsans_fallback_src := DroidSansFallback.ttf
-extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf
-else
 droidsans_fallback_src := DroidSansFallbackFull.ttf
 extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf DroidSansEthiopic-Regular.ttf
 endif  # SMALLER_FONT_FOOTPRINT
 
+################################
 include $(CLEAR_VARS)
 LOCAL_MODULE := DroidSansFallback.ttf
 LOCAL_SRC_FILES := $(droidsans_fallback_src)
@@ -81,3 +82,46 @@
 font_symlink :=
 droidsans_fallback_src :=
 extra_droidsans_fonts :=
+
+################################
+# Build the rest font files as prebuilt.
+
+# $(1): The source file name in LOCAL_PATH.
+#       It also serves as the module name and the dest file name.
+define build-one-font-module
+$(eval include $(CLEAR_VARS))\
+$(eval LOCAL_MODULE := $(1))\
+$(eval LOCAL_SRC_FILES := $(1))\
+$(eval LOCAL_MODULE_CLASS := ETC)\
+$(eval LOCAL_MODULE_TAGS := optional)\
+$(eval LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts)\
+$(eval include $(BUILD_PREBUILT))
+endef
+
+font_src_files := \
+    Roboto-Regular.ttf \
+    Roboto-Bold.ttf \
+    Roboto-Italic.ttf \
+    Roboto-BoldItalic.ttf \
+    DroidSansArabic.ttf \
+    DroidNaskh-Regular.ttf \
+    DroidSansHebrew-Regular.ttf \
+    DroidSansHebrew-Bold.ttf \
+    DroidSansThai.ttf \
+    DroidSerif-Regular.ttf \
+    DroidSerif-Bold.ttf \
+    DroidSerif-Italic.ttf \
+    DroidSerif-BoldItalic.ttf \
+    DroidSansMono.ttf \
+    DroidSansArmenian.ttf \
+    DroidSansGeorgian.ttf \
+    AndroidEmoji.ttf \
+    Clockopia.ttf \
+    AndroidClock.ttf \
+    AndroidClock_Highlight.ttf \
+    AndroidClock_Solid.ttf \
+
+$(foreach f, $(font_src_files), $(call build-one-font-module, $(f)))
+
+build-one-font-module :=
+font_src_files :=
diff --git a/data/fonts/DroidSansArabic.ttf b/data/fonts/DroidSansArabic.ttf
new file mode 100644
index 0000000..bdefaac
--- /dev/null
+++ b/data/fonts/DroidSansArabic.ttf
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 47cdae7..51b07e4 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -25,7 +25,7 @@
 <familyset>
     <family>
         <fileset>
-            <file>DroidNaskh-Regular.ttf</file>
+            <file>DroidSansArabic.ttf</file>
         </fileset>
     </family>
     <family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 9dca329..458f85b 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -14,33 +14,30 @@
 
 # Warning: this is actually a product definition, to be inherited from
 
-# On space-constrained devices, we include a subset of fonts:
-# First, core/required fonts
 PRODUCT_COPY_FILES := \
-    frameworks/base/data/fonts/Roboto-Regular.ttf:system/fonts/Roboto-Regular.ttf \
-    frameworks/base/data/fonts/Roboto-Bold.ttf:system/fonts/Roboto-Bold.ttf \
-    frameworks/base/data/fonts/Roboto-Italic.ttf:system/fonts/Roboto-Italic.ttf \
-    frameworks/base/data/fonts/Roboto-BoldItalic.ttf:system/fonts/Roboto-BoldItalic.ttf \
-    frameworks/base/data/fonts/DroidNaskh-Regular.ttf:system/fonts/DroidNaskh-Regular.ttf \
-    frameworks/base/data/fonts/DroidSansHebrew-Regular.ttf:system/fonts/DroidSansHebrew-Regular.ttf \
-    frameworks/base/data/fonts/DroidSansHebrew-Bold.ttf:system/fonts/DroidSansHebrew-Bold.ttf \
-    frameworks/base/data/fonts/DroidSansThai.ttf:system/fonts/DroidSansThai.ttf \
-    frameworks/base/data/fonts/DroidSerif-Regular.ttf:system/fonts/DroidSerif-Regular.ttf \
-    frameworks/base/data/fonts/DroidSerif-Bold.ttf:system/fonts/DroidSerif-Bold.ttf \
-    frameworks/base/data/fonts/DroidSerif-Italic.ttf:system/fonts/DroidSerif-Italic.ttf \
-    frameworks/base/data/fonts/DroidSerif-BoldItalic.ttf:system/fonts/DroidSerif-BoldItalic.ttf \
-    frameworks/base/data/fonts/DroidSansMono.ttf:system/fonts/DroidSansMono.ttf \
-    frameworks/base/data/fonts/DroidSansArmenian.ttf:system/fonts/DroidSansArmenian.ttf \
-    frameworks/base/data/fonts/DroidSansGeorgian.ttf:system/fonts/DroidSansGeorgian.ttf \
-    frameworks/base/data/fonts/AndroidEmoji.ttf:system/fonts/AndroidEmoji.ttf \
-    frameworks/base/data/fonts/Clockopia.ttf:system/fonts/Clockopia.ttf \
-    frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \
-    frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \
-    frameworks/base/data/fonts/AndroidClock_Solid.ttf:system/fonts/AndroidClock_Solid.ttf \
     frameworks/base/data/fonts/system_fonts.xml:system/etc/system_fonts.xml \
     frameworks/base/data/fonts/fallback_fonts.xml:system/etc/fallback_fonts.xml
 
-# Next, include additional fonts, depending on how much space we have.
-# Details see module definitions in Android.mk.
 PRODUCT_PACKAGES := \
-    DroidSansFallback.ttf
+    DroidSansFallback.ttf \
+    Roboto-Regular.ttf \
+    Roboto-Bold.ttf \
+    Roboto-Italic.ttf \
+    Roboto-BoldItalic.ttf \
+    DroidSansArabic.ttf \
+    DroidNaskh-Regular.ttf \
+    DroidSansHebrew-Regular.ttf \
+    DroidSansHebrew-Bold.ttf \
+    DroidSansThai.ttf \
+    DroidSerif-Regular.ttf \
+    DroidSerif-Bold.ttf \
+    DroidSerif-Italic.ttf \
+    DroidSerif-BoldItalic.ttf \
+    DroidSansMono.ttf \
+    DroidSansArmenian.ttf \
+    DroidSansGeorgian.ttf \
+    AndroidEmoji.ttf \
+    Clockopia.ttf \
+    AndroidClock.ttf \
+    AndroidClock_Highlight.ttf \
+    AndroidClock_Solid.ttf \
diff --git a/docs/html/design/get-started/ui-overview.html b/docs/html/design/get-started/ui-overview.html
index b08c743..bd5ff9c 100644
--- a/docs/html/design/get-started/ui-overview.html
+++ b/docs/html/design/get-started/ui-overview.html
@@ -153,12 +153,12 @@
   </div>
 </div>
 
-<h2>UI Bars</h2>
+<h2>System Bars</h2>
 
-<p>The UI bars are screen areas dedicated to the display of notifications, communication of device
-status, and device navigation. Typically the UI bars are displayed concurrently with your app. Apps
-that display immersive content, such as movies or images, can temporarily hide the UI bars to allow
-the user to enjoy full screen content without distraction.</p>
+<p>The system bars are screen areas dedicated to the display of notifications, communication of device
+status, and device navigation. Typically the system bars are displayed concurrently with your app.
+Apps that display immersive content, such as movies or images, can temporarily hide the system bars
+to allow the user to enjoy full screen content without distraction.</p>
 
 <img src="../static/content/ui_overview_system_ui.png">
 
@@ -177,8 +177,9 @@
   Recents, and also displays a menu for apps written for Android 2.3 or earlier.</p>
 </li>
 <li>
-<h4>System Bar</h4>
-<p>Combines the status and navigation bars for display on tablet form factors.</p>
+<h4>Combined Bar</h4>
+<p>On tablet form factors the status and navigation bars are combined into a single bar at the
+  bottom of the screen.</p>
 </li>
 </ol>
 
diff --git a/docs/html/design/patterns/actionbar.html b/docs/html/design/patterns/actionbar.html
index 99ae2d7..911c549 100644
--- a/docs/html/design/patterns/actionbar.html
+++ b/docs/html/design/patterns/actionbar.html
@@ -133,7 +133,7 @@
 you wish.
 Important: If the app is currently not displaying the top-level screen, be sure to display the Up
 caret to the left of the app icon, so the user can navigate up the hierarchy. For more discussion of
-Up navigation, see the "Navigation" pattern.
+Up navigation, see the <a href="../patterns/navigation.html">Navigation</a> pattern.
 
 <div class="figure">
   <img src="../static/content/action_bar_pattern_up_app_icon.png">
@@ -369,6 +369,22 @@
 <p>If either F, I, or T apply, then it's appropriate for the action bar. Otherwise, it belongs in the
 action overflow.</p>
 
+<p>
+
+Pre-defined glyphs should be used for certain common actions such as "refresh" and "share." The
+download link below provides a package with icons that are scaled for various screen densities and
+are suitable for use with the Holo Light and Holo Dark themes. The package also includes unstyled
+icons that you can modify to match your theme, in addition to Adobe&reg; Illustrator&reg; source
+files for further customization.
+
+</p>
+<p>
+
+<a href="../static/download/action_bar_icons-v4.0.zip">Download the Action Bar Icon
+Pack</a>
+
+</p>
+
 <div class="layout-content-row">
   <div class="layout-content-col span-6">
 
diff --git a/docs/html/design/patterns/app-structure.html b/docs/html/design/patterns/app-structure.html
index b87f402..fb9205b 100644
--- a/docs/html/design/patterns/app-structure.html
+++ b/docs/html/design/patterns/app-structure.html
@@ -159,9 +159,9 @@
 
     <img src="../static/content/app_structure_market.png">
     <div class="figure-caption">
-      Market's start screen primarily allows navigation into the stores for Apps, Music, Books, and
-      Games. It is also enriched with tailored recommendations and promotions that surface content
-      of interest to the user. Search is readily available from the action bar.
+      Market's start screen primarily allows navigation into the stores for Apps, Music, Books,
+      Movies and Games. It is also enriched with tailored recommendations and promotions that
+      surface content of interest to the user. Search is readily available from the action bar.
     </div>
 
   </div>
diff --git a/docs/html/design/patterns/navigation.html b/docs/html/design/patterns/navigation.html
index aabfc39..cad3682 100644
--- a/docs/html/design/patterns/navigation.html
+++ b/docs/html/design/patterns/navigation.html
@@ -131,7 +131,7 @@
 <p>The Back key also supports a few behaviors not directly tied to screen-to-screen navigation:</p>
 <ul>
 <li>Back dismisses floating windows (dialogs, popups)</li>
-<li>Back dismisses contextual action bars, and remove highlight from selected items</li>
+<li>Back dismisses contextual action bars, and removes the highlight from the selected items</li>
 <li>Back hides the onscreen keyboard (IME)</li>
 </ul>
 <h2>Navigation Within Your App</h2>
@@ -189,18 +189,19 @@
 <h4>App-to-app navigation</h4>
 <p>When navigating deep into your app's hierarchy directly from another app via an intent, Back will
 return to the referring app.</p>
-<p>The Up button is handled is follows:
+<p>The Up button is handled as follows:
 - If the destination screen is typically reached from one particular screen within your app, Up
   should navigate to that screen.
 - Otherwise, Up should navigate to the topmost ("Home") screen of your app.</p>
-<p>For example, after choosing to share a book being view in Market, the user navigates directly to the
-Gmail's compose screen. From there, Up returns to the Inbox (which happens to be both the typical
-referrer to compose, as well as the topmost screen of the app), while Back returns to Market.</p>
+<p>For example, after choosing to share a book being viewed in Market, the user navigates directly to
+Gmail's compose screen. From there, Up returns to the Inbox (which happens to be both the
+typical referrer to compose, as well as the topmost screen of the app), while Back returns to
+Market.</p>
 
 <img src="../static/content/navigation_from_outside_up.png">
 
 <h4>System-to-app navigation</h4>
-<p>If the your app was reached via the system mechanisms of notifications or home screen widgets, Up
+<p>If your app was reached via the system mechanisms of notifications or home screen widgets, Up
 behaves as described for app-to-app navigation, above.</p>
 <p>For the Back key, you should make navigation more predictably by inserting into the task's back
 stack the complete upward navigation path to the app's topmost screen. This way, a user who has
diff --git a/docs/html/design/patterns/notifications.html b/docs/html/design/patterns/notifications.html
index acec306..c5045aed 100644
--- a/docs/html/design/patterns/notifications.html
+++ b/docs/html/design/patterns/notifications.html
@@ -200,7 +200,7 @@
 the user is taken to a hierarchy level below your app's top-level, insert navigation into your app's
 back stack to allow them to navigate to your app's top level using the system back key. For more
 information, see the chapter on <em>System-to-app navigation</em> in the
-<a href="../patterns/notifications.html">Navigation</a> design pattern.</p>
+<a href="../patterns/navigation.html">Navigation</a> design pattern.</p>
 <h4>Timestamps for time sensitive events</h4>
 <p>By default, standard Android notifications include a timestamp in the upper right corner. Consider
 whether the timestamp is valuable in the context of your notification. If the timestamp is not
diff --git a/docs/html/design/static/download/action_bar_icons-v4.0.zip b/docs/html/design/static/download/action_bar_icons-v4.0.zip
new file mode 100644
index 0000000..4568894
--- /dev/null
+++ b/docs/html/design/static/download/action_bar_icons-v4.0.zip
Binary files differ
diff --git a/docs/html/design/style/iconography.html b/docs/html/design/style/iconography.html
index 663770b..5d5d200 100644
--- a/docs/html/design/style/iconography.html
+++ b/docs/html/design/style/iconography.html
@@ -193,10 +193,28 @@
 
 <h2 id="actionbar">Action Bar</h2>
 
-<p>Action bar icons are graphic buttons that represent the most important actions people can take
-within your app. Each one should employ a simple metaphor representing a single concept that most
-people can grasp at a glance.</p>
+<p>
 
+Action bar icons are graphic buttons that represent the most important actions people can take
+within your app. Each one should employ a simple metaphor representing a single concept that most
+people can grasp at a glance.
+
+</p>
+<p>
+
+Pre-defined glyphs should be used for certain common actions such as "refresh" and "share." The
+download link below provides a package with icons that are scaled for various screen densities and
+are suitable for use with the Holo Light and Holo Dark themes. The package also includes unstyled
+icons that you can modify to match your theme, in addition to Adobe&reg; Illustrator&reg; source
+files for further customization.
+
+</p>
+<p>
+
+<a href="../static/download/action_bar_icons-v4.0.zip">Download the Action Bar Icon
+Pack</a>
+
+</p>
 
 <div class="layout-content-row">
   <div class="layout-content-col span-4">
diff --git a/docs/html/guide/appendix/market-filters.jd b/docs/html/guide/appendix/market-filters.jd
index 07b9370..d9b2155 100644
--- a/docs/html/guide/appendix/market-filters.jd
+++ b/docs/html/guide/appendix/market-filters.jd
@@ -165,10 +165,10 @@
 
     <p><strong>Example 1</strong><br />
     The manifest declares <code>&lt;uses-sdk android:minSdkVersion="3"&gt;</code>
-    and does not does not include a <code>&lt;supports-screens&gt;</code> element.
-    <strong>Result</strong>: Android Market will not show the app to a user of a
-    small-screen device, but will show it to users of normal and large-screen
-    devices,  users, unless  other filters apply. </p>
+    and does not include a <code>&lt;supports-screens&gt;</code> element.
+    <strong>Result</strong>: Android Market does not show the app to a user of a
+    small-screen device, but does show it to users of normal and large-screen
+    devices, unless  other filters also exclude those devices. </p>
     <p><strong>Example 2<br />
     </strong>The manifest declares <code>&lt;uses-sdk android:minSdkVersion="3"
     android:targetSdkVersion="4"&gt;</code> and does not include a
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index c4d08ed..d390ec1 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -154,6 +154,14 @@
     <td><code>0489</code></td>
   </tr>
   <tr>
+    <td>Fujitsu</td>
+    <td><code>04C5</code></td>
+  </tr>
+  <tr>
+    <td>Fujitsu Toshiba</td>
+    <td><code>04C5</code></td>
+  </tr>
+  <tr>
     <td>Garmin-Asus</td>
     <td><code>091E</code></td>
   </tr>
@@ -246,6 +254,10 @@
     <td><code>04DD</code></td>
   </tr>
   <tr>
+    <td>Sony</td>
+    <td><code>054C</code></td>
+  </tr>
+  <tr>
     <td>Sony Ericsson</td>
     <td><code>0FCE</code></td>
   </tr>
diff --git a/docs/html/guide/developing/devices/managing-avds.jd b/docs/html/guide/developing/devices/managing-avds.jd
index 1817ce7..e70a0bb 100644
--- a/docs/html/guide/developing/devices/managing-avds.jd
+++ b/docs/html/guide/developing/devices/managing-avds.jd
@@ -233,13 +233,5 @@
 
       <td>hw.lcd.density</td>
     </tr>
-
-    <tr>
-      <td>Trackball support</td>
-
-      <td>Whether there is a trackball present.</td>
-
-      <td>hw.trackBall</td>
-    </tr>
   </table>
 
diff --git a/docs/html/guide/developing/projects/index.jd b/docs/html/guide/developing/projects/index.jd
index ac8a1a5..63e67cd 100644
--- a/docs/html/guide/developing/projects/index.jd
+++ b/docs/html/guide/developing/projects/index.jd
@@ -179,8 +179,9 @@
 
     <dd>Customizable computer-specific properties for the build system. If you use Ant to build
     the project, this contains the path to the SDK installation. Because the content of the file
-    is specific to the local installation of the SDK, maintained it in a source
-    revision control system. If you use Eclipse, this file is not used.</dd>
+    is specific to the local installation of the SDK, the <code>local.properties</code> should not
+be maintained in a source revision control system. If you use Eclipse, this file is not
+used.</dd>
 
     <dt><code>ant.properties</code></dt>
 
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index ee4c48e..4a9a684 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -8,15 +8,16 @@
 <ul>
 
   <li>
-    <h2><span class="en">Android Basics</span>
-        <span class="de" style="display:none">Einführung in Android</span>
-        <span class="es" style="display:none">Información básica sobre Android</span>
-        <span class="fr" style="display:none">Présentation d'Android</span>
-        <span class="it" style="display:none">Nozioni di base su Android</span>
-        <span class="ja" style="display:none">Android の基本</span>
-        <span class="zh-CN" style="display:none">Android 基础知识</span>
-        <span class="zh-TW" style="display:none">Android 簡介</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Android Basics</span>
+      <span class="de" style="display:none">Einführung in Android</span>
+      <span class="es" style="display:none">Información básica sobre Android</span>
+      <span class="fr" style="display:none">Présentation d'Android</span>
+      <span class="it" style="display:none">Nozioni di base su Android</span>
+      <span class="ja" style="display:none">Android の基本</span>
+      <span class="zh-CN" style="display:none">Android 基础知识</span>
+      <span class="zh-TW" style="display:none">Android 簡介</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/basics/what-is-android.html">
         <span class="en">What Is Android?</span>
@@ -46,7 +47,7 @@
   </li>
 
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">Framework Topics</span>
       <span class="de" style="display:none">Framework-Themen</span>
       <span class="es" style="display:none">Temas sobre el framework</span>
@@ -55,7 +56,7 @@
       <span class="ja" style="display:none">フレームワーク トピック</span>
       <span class="zh-CN" style="display:none">框架主题</span>
       <span class="zh-TW" style="display:none">架構主題</span>
-    </h2>
+    </span>
     <ul>
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>guide/topics/fundamentals/activities.html">
@@ -87,10 +88,24 @@
             <span class="en">Content Providers</span>
           </a></div>
           <ul>
-            <li><a href="<?cs var:toroot ?>guide/topics/providers/calendar-provider.html">
-                  <span class="en">Calendar Provider</span></a>
-                  <span class="new">new!</span>
-                </li>
+            <li>
+                <a href="<?cs var:toroot ?>guide/topics/providers/content-provider-basics.html">
+                    <span class="en">Content Provider Basics</span>
+                </a>
+                <span class="new">new!</span>
+            </li>
+            <li>
+                <a href="<?cs var:toroot ?>guide/topics/providers/content-provider-creating.html">
+                    <span class="en">Creating a Content Provider</span>
+                </a>
+                <span class="new">new!</span>
+            </li>
+            <li>
+                <a href="<?cs var:toroot ?>guide/topics/providers/calendar-provider.html">
+                    <span class="en">Calendar Provider</span>
+                </a>
+                <span class="new">new!</span>
+            </li>
           </ul>
       </li>
       <li><a href="<?cs var:toroot ?>guide/topics/intents/intents-filters.html">
@@ -116,7 +131,7 @@
               </a></li>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/menus.html">
                <span class="en">Menus</span>
-              </a></li>
+              </a> <span class="new">updated</span></li>
           <li><a href="<?cs var:toroot ?>guide/topics/ui/actionbar.html">
                <span class="en">Action Bar</span>
               </a></li>
@@ -429,9 +444,9 @@
   </li>
 
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">Android Market Topics</span>
-    </h2>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/publishing/publishing.html">
           <span class="en">Publishing on Android Market</span>
@@ -475,15 +490,16 @@
 
 
   <li>
-    <h2><span class="en">Developing</span>
-               <span class="de" style="display:none">Entwicklung</span>
-               <span class="es" style="display:none">Desarrollo</span>
-               <span class="fr" style="display:none">Développement</span>
-               <span class="it" style="display:none">Sviluppo</span>
-               <span class="ja" style="display:none">開発</span>
-               <span class="zh-CN" style="display:none">开发</span>
-               <span class="zh-TW" style="display:none">開發</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Developing</span>
+      <span class="de" style="display:none">Entwicklung</span>
+      <span class="es" style="display:none">Desarrollo</span>
+      <span class="fr" style="display:none">Développement</span>
+      <span class="it" style="display:none">Sviluppo</span>
+      <span class="ja" style="display:none">開発</span>
+      <span class="zh-CN" style="display:none">开发</span>
+      <span class="zh-TW" style="display:none">開發</span>
+    </span>
     <ul>
   <!--<li><a href="">Developing for Android</a></li>
       signing, upgrading, selecting a package name, select device profile, touch, trackball, dpad available, etc. -->
@@ -669,15 +685,16 @@
   </li>
 
   <li>
-    <h2><span class="en">Publishing</span>
-        <span class="de" style="display:none">Veröffentlichung</span>
-        <span class="es" style="display:none">Publicación</span>
-        <span class="fr" style="display:none">Publication</span>
-        <span class="it" style="display:none">Pubblicazione</span>
-        <span class="ja" style="display:none">公開</span>
-        <span class="zh-CN" style="display:none">发布</span>
-        <span class="zh-TW" style="display:none">發佈</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Publishing</span>
+      <span class="de" style="display:none">Veröffentlichung</span>
+      <span class="es" style="display:none">Publicación</span>
+      <span class="fr" style="display:none">Publication</span>
+      <span class="it" style="display:none">Pubblicazione</span>
+      <span class="ja" style="display:none">公開</span>
+      <span class="zh-CN" style="display:none">发布</span>
+      <span class="zh-TW" style="display:none">發佈</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/publishing/publishing_overview.html">
             <span class="en">Publishing Overview</span>
@@ -719,15 +736,16 @@
   </li>
 
   <li>
-    <h2><span class="en">Best Practices</span>
-               <span class="de" style="display:none">Bewährte Verfahren</span>
-               <span class="es" style="display:none">Prácticas recomendadas</span>
-               <span class="fr" style="display:none">Meilleures pratiques</span>
-               <span class="it" style="display:none">Best practice</span>
-               <span class="ja" style="display:none">ベスト プラクティス</span>
-               <span class="zh-CN" style="display:none">最佳实践</span>
-               <span class="zh-TW" style="display:none">最佳實務</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Best Practices</span>
+      <span class="de" style="display:none">Bewährte Verfahren</span>
+      <span class="es" style="display:none">Prácticas recomendadas</span>
+      <span class="fr" style="display:none">Meilleures pratiques</span>
+      <span class="it" style="display:none">Best practice</span>
+      <span class="ja" style="display:none">ベスト プラクティス</span>
+      <span class="zh-CN" style="display:none">最佳实践</span>
+      <span class="zh-TW" style="display:none">最佳實務</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/practices/compatibility.html">
             <span class="en">Compatibility</span>
@@ -823,8 +841,9 @@
   </li>
 
   <li>
-    <h2><span class="en">Web Applications</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Web Applications</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/webapps/index.html">
             <span class="en">Web Apps Overview</span>
@@ -845,15 +864,16 @@
   </li>
 
   <li>
-    <h2><span class="en">Appendix</span>
-               <span class="de" style="display:none">Anhang</span>
-               <span class="es" style="display:none">Apéndice</span>
-               <span class="fr" style="display:none">Annexes</span>
-               <span class="it" style="display:none">Appendice</span>
-               <span class="ja" style="display:none">付録</span>
-               <span class="zh-CN" style="display:none">附录</span>
-               <span class="zh-TW" style="display:none">附錄</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Appendix</span>
+      <span class="de" style="display:none">Anhang</span>
+      <span class="es" style="display:none">Apéndice</span>
+      <span class="fr" style="display:none">Annexes</span>
+      <span class="it" style="display:none">Appendice</span>
+      <span class="ja" style="display:none">付録</span>
+      <span class="zh-CN" style="display:none">附录</span>
+      <span class="zh-TW" style="display:none">附錄</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>guide/appendix/api-levels.html">
             <span class="en">Android API Levels</span>
diff --git a/docs/html/guide/practices/tablets-and-handsets.jd b/docs/html/guide/practices/tablets-and-handsets.jd
index 3f4aaa9..8e07a08 100644
--- a/docs/html/guide/practices/tablets-and-handsets.jd
+++ b/docs/html/guide/practices/tablets-and-handsets.jd
@@ -99,7 +99,8 @@
 
 <p>You can enable items from the options menu to appear directly in the action bar as "action
 items". You can also add navigation features to the action bar, such as tabs or a drop-down list,
-and use the application icon to supplement the system's BACK behavior with the option to navigate to
+and use the application icon to supplement the system's <em>Back</em> button behavior with the option to
+navigate to
 your application's "home" activity or "up" the application's structural hierarchy.</p>
 
 <p>This guide provides some tips for using the action bar in ways that support both tablets and
@@ -458,7 +459,8 @@
 developer guide, you can use the application icon in the action bar to facilitate user navigation
 when appropriate&mdash;either as a method to get back to the "home" activity (similar to clicking
 the logo on a web site) or as a way to navigate up the application's structural hierarchy. Although
-it might seem similar to the standard BACK navigation in some cases, the up navigation option
+it might seem similar to the standard <em>Back</em> navigation in some cases, the up navigation
+option
 provides a more predictable navigation method for situations in which the user may have entered
 from an external location, such as a notification, app widget, or a different application.</p>
 
diff --git a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
index 5faa7ec..9be72ee 100644
--- a/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/activity_task_design.jd
@@ -42,7 +42,8 @@
       <li><a href=#activities_added_to_task_tip>Allow activities to add to current task</a></li>
       <li><a href=#notifications_get_back_tip>Notifications and App Widgets should provide consistent back behavior</li>
       <li><a href=#use_notification_tip>Use the notification system</a></li>
-      <li><a href=#taking_over_back_key>Don't take over BACK key unless you absolutely need to</a></li>
+      <li><a href=#taking_over_back_key>Don't take over <em>Back</em> button unless you absolutely
+need to</a></li>
     </ol>
   </li>
 </ol>
@@ -241,8 +242,8 @@
   Android system keeps a linear navigation history of activities the
   user has visited. This is the <em>activity stack</em>, also known as the
   back stack. In general, when a user starts a new activity, it is added
-  to the activity stack, so that pressing BACK displays the previous
-  activity on the stack. However, the user cannot use the BACK key to go
+  to the activity stack, so that pressing <em>Back</em> displays the previous
+  activity on the stack. However, the user cannot use the <em>Back</em> button to go
   back further than the last visit to Home. The adding of an activity to
   the current stack happens whether or not that activity begins a new 
   <a href=#tasks title=task>task</a> (as long as that task was started
@@ -256,10 +257,11 @@
   Activities are the only things that can be added to the activity stack
   &mdash; views, windows, menus, and dialogs cannot. That is, when
   designing the navigation, if you have screen A and you want the user
-  to be able go to a subsequent screen B and then use the BACK key to go
+  to be able go to a subsequent screen B and then use the <em>Back</em> button to go
   back to screen A, then the screen A needs to be implemented as an
   activity. The one exception to this rule is if your application 
-  <a href="#taking_over_back_key">takes control of the BACK key</a> and manages the navigation
+  <a href="#taking_over_back_key">takes control of the <em>Back</em> button</a> and manages the
+navigation
 itself.
 </p>
 
@@ -287,7 +289,7 @@
   launcher, Home screen shortcut or "Recent tasks" switcher (a long
   press on Home on some devices). The user can return to a task by
   choosing the icon for its root activity the same way they started the
-  task. Once inside a task, the BACK key goes to previous activities in
+  task. Once inside a task, the <em>Back</em> button goes to previous activities in
   that task. The activity stack is made up of one or more tasks.
 </p>
 
@@ -331,7 +333,7 @@
   Browser are two applications that do this. For example, choosing an
   address in an email starts the Maps activity as a new task, and
   choosing a link in an email starts the Browser activity as a new
-  task. In these cases, the BACK key will return to the previous
+  task. In these cases, the <em>Back</em> button will return to the previous
   activity in a different task (Email), because it was not started from
   Home.
 </p>
@@ -341,7 +343,7 @@
 
 <p>
   The following examples illustrate basic principles for applications,
-  activities, the activity stack, the BACK key, tasks and intents.  It
+  activities, the activity stack, the <em>Back</em> button, tasks and intents.  It
   shows how the system responds to user actions such as starting
   activities and switching between tasks.  With most of these examples
   you can follow along, launching activities on your device as
@@ -367,19 +369,20 @@
   <img src={@docRoot}images/activity_task_design/HomeTaskBasics1a.png>
 </p>
 
-<h3 id=navigating_away_from_an_activity>Navigating Away from an Activity with BACK and HOME keys</h3>
+<h3 id=navigating_away_from_an_activity>Navigating Away from an Activity with <em>Back</em> and
+<em>Home</em> buttons</h3>
 
 <p>
   An activity can keep or lose its state depending on how the user
-  leaves the activity &mdash; by the HOME or BACK key.
+  leaves the activity &mdash; by the <em>Home</em> or <em>Back</em> button.
 </p>
 
 <p>
-  By default, pressing the BACK key finishes (destroys) the current
+  By default, pressing the <em>Back</em> button finishes (destroys) the current
   activity and displays the previous activity to the user. In the
   following figure, the user starts email by touching the Email icon in
   the Home screen, which displays a list of email messages. The user
-  scrolls down the list (changing its initial state). Pressing BACK
+  scrolls down the list (changing its initial state). Pressing <em>Back</em>
   destroys the List Messages activity and returns to the previous
   activity, which is Home. If the user re-launches Email, it would
   re-load the messages and display its initial, non-scrolled state.
@@ -390,15 +393,15 @@
 </p>
 
 <p>
-  In the above example, pressing BACK goes to Home because it was the
+  In the above example, pressing <em>Back</em> goes to Home because it was the
   last activity the user was viewing. But if the user had gotten to List
-  Message from some other activity, then pressing BACK would have
+  Message from some other activity, then pressing <em>Back</em> would have
   returned there.
 </p>
 
 <p>
   By contrast, the next figure shows the user leaving List Messages by
-  pressing HOME instead of BACK &mdash; the List Messages activity is
+  pressing <em>Home</em> instead of <em>Back</em> &mdash; the List Messages activity is
   stopped and moved to the background rather than being
   destroyed. Starting Email again from its icon would simply bring the
   List Messages activity to the foreground (changing it from stopped to
@@ -423,8 +426,8 @@
 
 <p>
   In addition, not all activities have the behavior that they are
-  destroyed when BACK is pressed. When the user starts playing music in
-  the Music application and then presses BACK, the application overrides
+  destroyed when <em>Back</em> is pressed. When the user starts playing music in
+  the Music application and then presses <em>Back</em>, the application overrides
   the normal back behavior, preventing the player activity from being
   destroyed, and continues playing music, even though its activity is no
   longer visible &mdash; as a visual substitute, the Music application
@@ -451,7 +454,7 @@
   activity to get a picture. This is a good example of re-use of the
   Gallery activity. The following figure illustrates the sequence of
   activities to do this (up to crop). This is how it's done: The user
-  chooses Contacts, selects the contact for viewing, chooses MENU &gt;
+  chooses Contacts, selects the contact for viewing, chooses <em>Menu</em> &gt;
   Edit contact and touches the picture field, which launches the Gallery
   activity. The user then chooses the picture they want, crops and saves
   it. Saving it causes the picture to be inserted into the picture field
@@ -484,12 +487,12 @@
   <b>Gallery Re-Uses Messaging for Sharing a Picture</b> - Sharing is
   another good example of one application re-using an activity from a
   different application. As shown in the following figure, the user
-  starts Gallery, picks a picture to view, chooses MENU &gt; Share, and
+  starts Gallery, picks a picture to view, chooses <em>Menu</em> &gt; Share, and
   picks "Messaging". This starts the Messaging activity, creates a new
   message and attaches the original picture to it. The user then fills
   in the "To" field, writes a short message and sends it. User focus
   remains in the Messaging program. If the user wants to go back to the
-  Gallery, they must press the BACK key. (The user can back up through
+  Gallery, they must press the <em>Back</em> button. (The user can back up through
   each activity all the way to Home.)
 </p>
 
@@ -552,7 +555,7 @@
   <ul>
     <li>
       State 2 - The user wants to do something else while they're
-      waiting, so they press HOME, which does not interrupt the map's
+      waiting, so they press <em>Home</em>, which does not interrupt the map's
       network connection and allows the map to continue loading in the
       background.
 
@@ -729,7 +732,7 @@
         <b>Start first task.</b> You want to send a text message and attach a photo. You would choose:
 
         <p>
-          Home &gt; Messaging &gt; New message &gt; MENU &gt; Attach
+          Home &gt; Messaging &gt; New message &gt; <em>Menu</em> &gt; Attach
           &gt; Pictures. This last step launches the picture gallery
           for picking a photo. Notice that picture gallery is an
           activity in a separate application.
@@ -961,7 +964,7 @@
           address in an email message (or web page), where the Maps
           activity is started to map the location. No result from maps
           is expected to be returned to the email message; the user
-          can return by pressing the BACK key. (Such an activity is
+          can return by pressing the <em>Back</em> button. (Such an activity is
           started with {@link
           android.content.Context#startActivity(android.content.Intent)
           startActivity()}.)
@@ -1102,20 +1105,21 @@
   convenience to respond to your message.
 </p>
 
-<h3 id=taking_over_back_key>Don't take over the BACK key unless you absolutely need to</h3>
+<h3 id=taking_over_back_key>Don't take over the <em>Back</em> button unless you absolutely need
+to</h3>
 
 <p>
   As a user navigates from one activity to the next, the system adds
   them to the activity stack. This forms a navigation history that is
-  accessible with the BACK key. Most activities are relatively limited
+  accessible with the <em>Back</em> button. Most activities are relatively limited
   in scope, with just one set of data, such as viewing a list of
   contacts, composing an email, or taking a photo. But what if your
   application is one big activity with several pages of content and
-  needs finer-grained control of the BACK key? Examples of such Google
+  needs finer-grained control of the <em>Back</em> button? Examples of such Google
   applications are the Browser, which can have several web pages open
   at once, and Maps, which can have several layers of geographic data
   to switch between. Both of these applications take control of the
-  BACK key and maintain their own internal back stacks that operate
+  <em>Back</em> button and maintain their own internal back stacks that operate
   only when these applications have focus.
 </p>
 
@@ -1124,7 +1128,7 @@
   information on a map to the user: displaying the location of a
   search result, displaying locations of friends, and displaying a
   line for a street path providing direction between points. Maps
-  stores these layers in its own history so the BACK key can return to
+  stores these layers in its own history so the <em>Back</em> button can return to
   a previous layer.
 </p>
 
@@ -1135,8 +1139,8 @@
   as Windows, Macintosh or Linux). For example, if you did a Google
   web search in one window of the Android Browser, clicking on a link
   in the search results displays a web page in that same window, and
-  then pressing BACK would to the search results page. Pressing
-  BACK goes to a previous window only if the current window was
+  then pressing <em>Back</em> would to the search results page. Pressing
+  <em>Back</em> goes to a previous window only if the current window was
   launched from that previous window.  If the user keeps pressing
   back, they will eventually leave the browser activity and return
   Home.
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design.jd b/docs/html/guide/practices/ui_guidelines/icon_design.jd
index 96aecf5..1c66185 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design.jd
@@ -42,8 +42,6 @@
 Templates Pack, v2.3 &raquo;</a></li>
 <li><a href="{@docRoot}shareables/icon_templates-v2.0.zip">Android Icon
 Templates Pack, v2.0 &raquo;</a></li>
-<li><a href="{@docRoot}shareables/icon_templates-v1.0.zip">Android Icon
-Templates Pack, v1.0 &raquo;</a></li>
 </ol>
 
 <h2>See also</h2>
diff --git a/docs/html/guide/practices/ui_guidelines/menu_design.jd b/docs/html/guide/practices/ui_guidelines/menu_design.jd
index 3edf33f..7576b6c 100644
--- a/docs/html/guide/practices/ui_guidelines/menu_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/menu_design.jd
@@ -71,7 +71,7 @@
   <ul>
     <li>The <em>Options menu</em> contains primary functionality that applies
         globally to the current activity or starts a related activity. 
-        It is typically invoked by a user pressing a hard button, often labeled MENU.</li>
+        It is typically invoked by a user pressing a hard button, often labeled <em>Menu</em>.</li>
     <li>The <em>Context menu</em> contains secondary functionality for the currently
         selected item.  It is typically invoked by a user's touch &amp; hold
         on an item.  Like on the Options menu, the operation can run either
@@ -109,10 +109,10 @@
 </p>
 
 <p>
-  On most devices, a user presses the MENU button to access the Options menu, 
+  On most devices, a user presses the <em>Menu</em> button to access the Options menu, 
   as shown in the screenshot below.  To close the menu, the user presses 
-  MENU again, or presses the BACK button. 
-  In fact, to cancel out of any menu, press the BACK button.  (Pressing the MENU
+  <em>Menu</em> again, or presses the <em>Back</em> button. 
+  In fact, to cancel out of any menu, press the <em>Back</em> button.  (Pressing the <em>Menu</em>
   button or touching outside the menu also works.)  Note that how to invoke this
   menu may be different on different devices.
 </p>
@@ -140,7 +140,7 @@
 
 <ul>
   <li>
-    <b>Options icon menu</b> - The first press of the MENU button displays a
+    <b>Options icon menu</b> - The first press of the <em>Menu</em> button displays a
     non-scrollable grid of icons at the bottom of the screen.  (On the G1
     phone, up to 6 buttons typically appear.)
   </li>
@@ -156,7 +156,7 @@
 
 <p>
   On some versions of Android, the user can display keyboard shortcuts in the
-  icon menu by long pressing the MENU button &mdash; the text in the icon menu
+  icon menu by long pressing the <em>Menu</em> button &mdash; the text in the icon menu
   alternates between the command names and their keyboard shortcuts (if any).
 </p>
 
@@ -299,7 +299,7 @@
   <a href="#location">location</a>) on the screen, put the command in the
   Context menu for that content.  If the command acts on no specific content
   or location, put it in the Options menu.  This separation of commands
-  is enforced by the system in the following way.  When you press the MENU
+  is enforced by the system in the following way.  When you press the <em>Menu</em>
   button to display the Options menu, the selected content becomes unselected,
   and so cannot be operated on.  For an explanation
   of why the content becomes unselected, see the article on
@@ -340,7 +340,7 @@
 
 <p>
   Before opening a Context menu, it has no visual representation that identifies
-  its presence (whereas the Options menu has the MENU button), and so is not
+  its presence (whereas the Options menu has the <em>Menu</em> button), and so is not
   particularly discoverable. 
   Therefore, in general, a Context menu should <em>duplicate</em> commands 
   found in the corresponding activity screen.  For example, while it's useful to
@@ -459,7 +459,8 @@
 <h3 id="a_dialog_should_not_have_an_options_menu">A dialog should not have an Options menu</h3>
 
 <p>
-  When a dialog is displayed, pressing the MENU button should do nothing.  This also holds true
+  When a dialog is displayed, pressing the <em>Menu</em> button should do nothing.  This also holds
+true
   for activities that look like dialogs.  A dialog box is recognizable by being
   smaller than full-screen, having zero to three buttons, is non-scrollable, and 
   possibly a list of selectable items that can include checkboxes or radio buttons.
@@ -475,7 +476,7 @@
 <h3 id="do_not_substitute_message">If an activity has no Options menu, do not display a message</h3>
 
 <p>
-  When the user presses the MENU button, if there is no Options menu, the system
+  When the user presses the <em>Menu</em> button, if there is no Options menu, the system
   currently does nothing.  We recommend you do not perform any action (such as
   displaying a message).  It's a better user experience for this behavior to be
   consistent across applications.
diff --git a/docs/html/guide/topics/fundamentals.jd b/docs/html/guide/topics/fundamentals.jd
index 661f5cb..d1a3786 100644
--- a/docs/html/guide/topics/fundamentals.jd
+++ b/docs/html/guide/topics/fundamentals.jd
@@ -243,7 +243,7 @@
 android.content.ContentResolver} object. This leaves a layer of abstraction between the content
 provider and the component requesting information (for security).</p>
 
-<p>There are separate methods for activiting each type of component:</p>
+<p>There are separate methods for activating each type of component:</p>
 <ul>
   <li>You can start an activity (or give it something new to do) by
 passing an {@link android.content.Intent} to {@link android.content.Context#startActivity
@@ -400,7 +400,7 @@
 requirements in your manifest file. That way, devices that do <em>not</em> have a camera and have an
 Android version <em>lower</em> than 2.1 cannot install your application from Android Market.</p>
 
-<p>However, you can also declare that your applicaiton uses the camera, but does not
+<p>However, you can also declare that your application uses the camera, but does not
 <em>require</em> it. In that case, your application must perform a check at runtime to determine
 if the device has a camera and disable any features that use the camera if one is not available.</p>
 
diff --git a/docs/html/guide/topics/fundamentals/activities.jd b/docs/html/guide/topics/fundamentals/activities.jd
index 3b31199..8736aa8 100644
--- a/docs/html/guide/topics/fundamentals/activities.jd
+++ b/docs/html/guide/topics/fundamentals/activities.jd
@@ -63,7 +63,7 @@
 activity starts, the previous activity is stopped, but the system preserves the activity
 in a stack (the "back stack"). When a new activity starts, it is pushed onto the back stack and
 takes user focus. The back stack abides to the basic "last in, first out" queue mechanism,
-so, when the user is done with the current activity and presses the BACK key, it
+so, when the user is done with the current activity and presses the <em>Back</em> button, it
 is popped from the stack (and destroyed) and the previous activity resumes. (The back stack is
 discussed more in the <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks
 and Back Stack</a> document.)</p>
@@ -649,7 +649,8 @@
 <p class="note"><strong>Note:</strong> There's no guarantee that {@link
 android.app.Activity#onSaveInstanceState onSaveInstanceState()} will be called before your
 activity is destroyed, because there are cases in which it won't be necessary to save the state
-(such as when the user leaves your activity using the BACK key, because the user is explicitly
+(such as when the user leaves your activity using the <em>Back</em> button, because the user is
+explicitly
 closing the activity). If the system calls {@link android.app.Activity#onSaveInstanceState
 onSaveInstanceState()}, it does so before {@link
 android.app.Activity#onStop onStop()} and possibly before {@link android.app.Activity#onPause
diff --git a/docs/html/guide/topics/fundamentals/fragments.jd b/docs/html/guide/topics/fundamentals/fragments.jd
index e8f6cd8..d4f9342 100644
--- a/docs/html/guide/topics/fundamentals/fragments.jd
+++ b/docs/html/guide/topics/fundamentals/fragments.jd
@@ -78,7 +78,7 @@
 fragment transaction, you can also add it to a back stack that's managed by the
 activity&mdash;each back stack entry in the activity is a record of the fragment transaction that
 occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards),
-by pressing the BACK button.</p>
+by pressing the <em>Back</em> button.</p>
 
 <p>When you add a fragment as a part of your activity layout, it lives in a {@link
 android.view.ViewGroup} inside the activity's view hierarchy and the fragment defines its own view
@@ -398,7 +398,7 @@
 the activity layout) or {@link android.app.FragmentManager#findFragmentByTag
 findFragmentByTag()} (for fragments that do or don't provide a UI).</li> 
   <li>Pop fragments off the back stack, with {@link
-android.app.FragmentManager#popBackStack()} (simulating a BACK command by the user).</li>
+android.app.FragmentManager#popBackStack()} (simulating a <em>Back</em> command by the user).</li>
   <li>Register a listener for changes to the back stack, with {@link
 android.app.FragmentManager#addOnBackStackChangedListener addOnBackStackChangedListener()}.</li>
 </ul>
@@ -439,7 +439,7 @@
 android.app.FragmentTransaction#commit()}, however, you might want to call {@link
 android.app.FragmentTransaction#addToBackStack addToBackStack()}, in order to add the transaction
 to a back stack of fragment transactions. This back stack is managed by the activity and allows
-the user to return to the previous fragment state, by pressing the BACK key.</p>
+the user to return to the previous fragment state, by pressing the <em>Back</em> button.</p>
 
 <p>For example, here's how you can replace one fragment with another, and preserve the previous
 state in the back stack:</p>
@@ -462,14 +462,14 @@
 layout container identified by the {@code R.id.fragment_container} ID. By calling {@link
 android.app.FragmentTransaction#addToBackStack addToBackStack()}, the replace transaction is
 saved to the back stack so the user can reverse the transaction and bring back the
-previous fragment by pressing the BACK key.</p>
+previous fragment by pressing the <em>Back</em> button.</p>
 
 <p>If you add multiple changes to the transaction (such as another {@link
 android.app.FragmentTransaction#add add()} or {@link android.app.FragmentTransaction#remove
 remove()}) and call {@link
 android.app.FragmentTransaction#addToBackStack addToBackStack()}, then all changes applied
 before you call {@link android.app.FragmentTransaction#commit commit()} are added to the
-back stack as a single transaction and the BACK key will reverse them all together.</p>
+back stack as a single transaction and the <em>Back</em> button will reverse them all together.</p>
 
 <p>The order in which you add changes to a {@link android.app.FragmentTransaction} doesn't matter,
 except:</p>
@@ -696,7 +696,7 @@
 <p>The most significant difference in lifecycle between an activity and a fragment is how one is
 stored in its respective back stack. An activity is placed into a back stack of activities
 that's managed by the system when it's stopped, by default (so that the user can navigate back
-to it with the BACK key, as discussed in <a
+to it with the <em>Back</em> button, as discussed in <a
 href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>).
 However, a fragment is placed into a back stack managed by the host activity only when you
 explicitly request that the instance be saved by calling {@link
diff --git a/docs/html/guide/topics/fundamentals/loaders.jd b/docs/html/guide/topics/fundamentals/loaders.jd
index 3aad204..ddd513b 100644
--- a/docs/html/guide/topics/fundamentals/loaders.jd
+++ b/docs/html/guide/topics/fundamentals/loaders.jd
@@ -491,7 +491,7 @@
 LoaderCursor</a> &#8212; A complete version of the
 snippet shown above.</li>
   <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LoaderThrottle.html"> LoaderThrottle</a> &#8212; An example of how to use throttling to
-reduce the number of queries a content provider does then its data changes.</li>
+reduce the number of queries a content provider does when its data changes.</li>
 </ul>
 
 <p>For information on downloading and installing the SDK samples, see <a
diff --git a/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd
index 086ba71..465cf54 100644
--- a/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd
+++ b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd
@@ -74,7 +74,7 @@
 suppose you have a two-pane layout using fragments, one of which is a list view (fragment A) and the
 other being a layout to display an item from the list (fragment B). When the user selects an item
 from the list, fragment B is replaced by a new fragment (fragment C). In this case, it might be
-desireable for the user to navigate back to reveal fragment B, using the BACK button.</p>
+desireable for the user to navigate back to reveal fragment B, using the <em>Back</em> button.</p>
 <p>In order to add fragment B to the back stack so that this is possible, you must call {@link
 android.app.FragmentTransaction#addToBackStack addToBackStack()} before you {@link
 android.app.FragmentTransaction#commit()} the transaction that replaces fragment B with fragment
@@ -94,22 +94,26 @@
 
 <p>When the current activity starts another, the new activity is pushed on the top of the stack and
 takes focus. The previous activity remains in the stack, but is stopped. When an activity
-stops, the system retains the current state of its user interface. When the user presses the BACK
+stops, the system retains the current state of its user interface. When the user presses the
+<em>Back</em>
 button, the current activity is popped from the top of the stack (the activity is destroyed) and the
 previous activity resumes (the previous state of its UI is restored). Activities in the stack are
 never rearranged, only pushed and popped from the stack&mdash;pushed onto the stack when started by
-the current activity and popped off when the user leaves it using the BACK button. As such, the back
+the current activity and popped off when the user leaves it using the <em>Back</em> button. As such,
+the back
 stack operates as a "last in, first out" object structure. Figure 1 visualizes
 this behavior with a timeline showing the progress between activities along with the current back
 stack at each point in time.</p>
 
 <img src="{@docRoot}images/fundamentals/diagram_backstack.png" alt="" />
 <p class="img-caption"><strong>Figure 1.</strong> A representation of how each new activity in a
-task adds an item to the back stack. When the user presses the BACK button, the current activity is
+task adds an item to the back stack. When the user presses the <em>Back</em> button, the current
+activity is
 destroyed and the previous activity resumes.</p>
 
 
-<p>If the user continues to press BACK, then each activity in the stack is popped off to reveal the
+<p>If the user continues to press <em>Back</em>, then each activity in the stack is popped off to
+reveal the
 previous one, until the user returns to the Home screen (or to whichever activity was running when
 the task began). When all activities are removed from the stack, the task no longer exists.</p>
 
@@ -124,11 +128,13 @@
 </div>
 
 <p>A task is a cohesive unit that can move to the "background" when users begin a new task or go
-to the Home screen, via the HOME button. While in the background, all the activities in the task are
+to the Home screen, via the <em>Home</em> button. While in the background, all the activities in the
+task are
 stopped, but the back stack for the task remains intact&mdash;the task has simply lost focus while
 another task takes place, as shown in figure 2. A task can then return to the "foreground" so users
 can pick up where they left off. Suppose, for example, that the current task (Task A) has three
-activities in its stack&mdash;two under the current activity. The user presses the HOME button, then
+activities in its stack&mdash;two under the current activity. The user presses the <em>Home</em>
+button, then
 starts a new application from the application launcher. When the Home screen appears, Task A goes
 into the background. When the new application starts, the system starts a task for that application
 (Task B) with its own stack of activities. After interacting with
@@ -137,7 +143,8 @@
 foreground&mdash;all three activities in its stack are intact and the activity at the top of the
 stack resumes. At
 this point, the user can also switch back to Task B by going Home and selecting the application icon
-that started that task (or by touching and holding the HOME button to reveal recent tasks and selecting
+that started that task (or by touching and holding the <em>Home</em> button to reveal recent tasks
+and selecting
 one). This is an example of multitasking on Android.</p>
 
 <p class="note"><strong>Note:</strong> Multiple tasks can be held in the background at once.
@@ -150,7 +157,8 @@
 that activity is created and popped onto the stack (rather than bringing any previous instance of
 the activity to the top). As such, one activity in your application might be instantiated multiple
 times (even from different tasks), as shown in figure 3. As such, if the user navigates backward
-using the BACK button, each instance of the activity is revealed in the order they were opened (each
+using the <em>Back</em> button, each instance of the activity is revealed in the order they were
+opened (each
 with their own UI state). However, you can modify this behavior if you do not want an activity to be
 instantiated more than once. How to do so is discussed in the later section about <a
 href="#ManagingTasks">Managing Tasks</a>.</p>
@@ -161,13 +169,15 @@
 <ul>
   <li>When Activity A starts Activity B, Activity A is stopped, but the system retains its state
 (such as scroll position and text entered into forms).
-If the user presses the BACK button while in Activity B, Activity A resumes with its state
+If the user presses the <em>Back</em> button while in Activity B, Activity A resumes with its state
 restored.</li>
-  <li>When the user leaves a task by pressing the HOME button, the current activity is stopped and
+  <li>When the user leaves a task by pressing the <em>Home</em> button, the current activity is
+stopped and
 its task goes into the background. The system retains the state of every activity in the task. If
 the user later resumes the task by selecting the launcher icon that began the task, the task comes
 to the foreground and resumes the activity at the top of the stack.</li>
-  <li>If the user presses the BACK button, the current activity is popped from the stack and
+  <li>If the user presses the <em>Back</em> button, the current activity is popped from the stack
+and
 destroyed. The previous activity in the stack is resumed. When an activity is destroyed, the system
 <em>does not</em> retain the activity's state.</li>
   <li>Activities can be instantiated multiple times, even from other tasks.</li>
@@ -256,7 +266,8 @@
 <p class="caution"><strong>Caution:</strong> Most applications should not interrupt the default
 behavior for activities and tasks. If you determine that it's necessary for your activity to modify
 the default behaviors, use caution and be sure to test the usability of the activity during
-launch and when navigating back to it from other activities and tasks with the BACK button. Be sure 
+launch and when navigating back to it from other activities and tasks with the <em>Back</em> button.
+Be sure 
 to test for navigation behaviors that might conflict with the user's expected behavior.</p>
 
 
@@ -320,8 +331,10 @@
 stack remains A-B-C-D. However, if an intent arrives for an activity of type B, then a new
 instance of B is added to the stack, even if its launch mode is {@code "singleTop"}.</p>
   <p class="note"><strong>Note:</strong> When a new instance of an activity is created,
-the user can press the BACK button to return to the previous activity. But when an existing instance of
-an activity handles a new intent, the user cannot press the BACK button to return to the state of
+the user can press the <em>Back</em> button to return to the previous activity. But when an existing
+instance of
+an activity handles a new intent, the user cannot press the <em>Back</em> button to return to the
+state of
 the activity before the new intent arrived in {@link android.app.Activity#onNewIntent
 onNewIntent()}.</p>
 </dd>
@@ -333,7 +346,7 @@
 android.app.Activity#onNewIntent onNewIntent()} method, rather than creating a new instance. Only
 one instance of the activity can exist at a time.
   <p class="note"><strong>Note:</strong> Although the activity starts in a new task, the
-BACK button still returns the user to the previous activity.</p></dd>
+<em>Back</em> button still returns the user to the previous activity.</p></dd>
 <dt>{@code "singleInstance"}.</dt>
   <dd>Same as {@code "singleTask"}, except that the system doesn't launch any other activities into
 the task holding the instance. The activity is always the single and only member of its task;
@@ -351,7 +364,7 @@
 intent.</p>
 
 <p>Regardless of whether an activity starts in a new task or in the same task as the activity that
-started it, the BACK button always takes the user to the previous activity. However, if you
+started it, the <em>Back</em> button always takes the user to the previous activity. However, if you
 start an activity that specifies the {@code singleTask} launch mode, then if an instance of
 that activity exists in a background task, that whole task is brought to the foreground. At this
 point, the back stack now includes all activities from the task brought forward, at the top of the
@@ -454,7 +467,8 @@
 However, it doesn't have to be.  If there's already an existing task with the same affinity as the
 new activity, the activity is launched into that task.  If not, it begins a new task.</p>
 
-<p>If this flag causes an activity to begin a new task and the user presses the HOME button to leave
+<p>If this flag causes an activity to begin a new task and the user presses the <em>Home</em> button
+to leave
 it, there must be some way for the user to navigate back to the task. Some entities (such as the
 notification manager) always start activities in an external task, never as part of their own, so
 they always put {@code FLAG_ACTIVITY_NEW_TASK} in the intents they pass to {@link
@@ -556,7 +570,8 @@
 and a {@link android.content.Intent#CATEGORY_LAUNCHER}
 filter. Imagine, for example, what could happen if the filter is missing: An intent launches a
 {@code "singleTask"} activity, initiating a new task, and the user spends some time working in
-that task.  The user then presses the HOME button. The task is now sent to the background and is
+that task.  The user then presses the <em>Home</em> button. The task is now sent to the background
+and is
 not visible. Now the user has no way to return to the task, because it is not represented in the
 application launcher.
 </p>
diff --git a/docs/html/guide/topics/intents/intents-filters.jd b/docs/html/guide/topics/intents/intents-filters.jd
index 3f94553..3ad3c93 100644
--- a/docs/html/guide/topics/intents/intents-filters.jd
+++ b/docs/html/guide/topics/intents/intents-filters.jd
@@ -247,7 +247,7 @@
 </tr><tr>
    <td>{@code CATEGORY_HOME}
    <td>The activity displays the home screen, the first screen the user sees when 
-       the device is turned on or when the HOME key is pressed.
+       the device is turned on or when the <em>Home</em> button is pressed.
 </tr><tr>
    <td>{@code CATEGORY_LAUNCHER}
    <td>The activity can be the initial activity of a task and is listed in 
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index e76a6be..f44901b 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -133,21 +133,21 @@
 it's ignored for all other activities in the task.
 
 <p>
-When the value is "{@code true}", every time users start the task again, they 
-are brought to its root activity, regardless of what they were last doing in 
-the task and regardless of whether they used BACK or HOME to last leave it.  
-When the value is "{@code false}", the task may be cleared of activities in 
+When the value is "{@code true}", every time users start the task again, they
+are brought to its root activity regardless of what they were last doing in
+the task and regardless of whether they used the <em>Back</em> or <em>Home</em> button to
+leave it. When the value is "{@code false}", the task may be cleared of activities in
 some situations (see the 
 <code><a href="#always">alwaysRetainTaskState</a></code> attribute), but not always.  
 </p>
 
 <p>
 Suppose, for example, that someone launches activity P from the home screen, 
-and from there goes to activity Q.  The user next presses HOME, and then returns 
+and from there goes to activity Q.  The user next presses <em>Home</em>, and then returns 
 to activity P.  Normally, the user would see activity Q, since that is what they 
 were last doing in P's task.  However, if P set this flag to "{@code true}", all 
 of the activities on top of it (Q in this case) were removed when the user pressed 
-HOME and the task went to the background.  So the user sees only P when returning 
+<em>Home</em> and the task went to the background.  So the user sees only P when returning 
 to the task.
 </p>
 
@@ -272,10 +272,11 @@
 </p></dd>
 
 <dt><a name="exclude"></a>{@code android:excludeFromRecents}</dt>
-<dd>Whether or not the activity should be excluded from the list of recently 
-launched activities that can be displayed to users &mdash; "{@code true}" if 
-it should be excluded, and "{@code false}" if it should be included.  
-The default value is "{@code false}".
+<dd>Whether or not the task initiated by this activity should be excluded from the list of recently
+used applications ("recent apps"). That is, when this activity is the root activity of a new task,
+this attribute determines whether the task should not appear in the list of recent apps. "{@code
+true}" if the task should be <em>excluded</em> from the list; "{@code false}" if it should be
+<em>included</em>. The default value is "{@code false}".
 </p></dd>
 
 <dt><a name="exported"></a>{@code android:exported}</dt>
@@ -501,7 +502,7 @@
 
 <p>Regardless of the launch mode that you choose, make sure to test the usability
 of the activity during launch and when navigating back to it from
-other activities and tasks using the BACK key. </p>
+other activities and tasks using the <em>Back</em> button. </p>
 
 <p>For more information on launch modes and their interaction with Intent
 flags, see the 
diff --git a/docs/html/guide/topics/providers/content-provider-basics.jd b/docs/html/guide/topics/providers/content-provider-basics.jd
new file mode 100644
index 0000000..40b5c3f
--- /dev/null
+++ b/docs/html/guide/topics/providers/content-provider-basics.jd
@@ -0,0 +1,1215 @@
+page.title=Content Provider Basics
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+
+
+                    <!-- In this document -->
+<h2>In this document</h2>
+<ol>
+    <li>
+        <a href="#Basics">Overview</a>
+        <ol>
+            <li>
+                <a href="#ClientProvider">Accessing a provider</a>
+            </li>
+            <li>
+                <a href="#ContentURIs">Content URIs</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#SimpleQuery">Retrieving Data from the Provider</a>
+        <ol>
+            <li>
+                <a href="#RequestPermissions">Requesting read access permission</a>
+            </li>
+            <li>
+                <a href="#Query">Constructing the query</a>
+            </li>
+            <li>
+                <a href="#DisplayResults">Displaying query results</a>
+            </li>
+            <li>
+                <a href="#GettingResults">Getting data from query results</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#Permissions">Content Provider Permissions</a>
+    </li>
+    <li>
+        <a href="#Modifications">Inserting, Updating, and Deleting Data</a>
+        <ol>
+            <li>
+                <a href="#Inserting">Inserting data</a>
+            </li>
+            <li>
+                <a href="#Updating">Updating data</a>
+            </li>
+            <li>
+                <a href="#Deleting">Deleting data</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#DataTypes">Provider Data Types</a>
+    </li>
+    <li>
+        <a href="#AltForms">Alternative Forms of Provider Access</a>
+        <ol>
+            <li>
+                <a href="#Batch">Batch access</a>
+            </li>
+            <li>
+                <a href="#Intents">Data access via intents</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#ContractClasses">Contract Classes</a>
+    </li>
+    <li>
+        <a href="#MIMETypeReference">MIME Type Reference</a>
+    </li>
+</ol>
+
+    <!-- Key Classes -->
+<h2>Key classes</h2>
+    <ol>
+        <li>
+            {@link android.content.ContentProvider}
+        </li>
+        <li>
+            {@link android.content.ContentResolver}
+        </li>
+        <li>
+            {@link android.database.Cursor}
+        </li>
+        <li>
+            {@link android.net.Uri}
+        </li>
+    </ol>
+
+    <!-- Related Samples -->
+<h2>Related Samples</h2>
+    <ol>
+        <li>
+        <a
+        href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
+        Cursor (People)</a>
+        </li>
+        <li>
+        <a
+        href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
+        Cursor (Phones)</a>
+        </li>
+    </ol>
+
+    <!-- See also -->
+<h2>See also</h2>
+    <ol>
+        <li>
+            <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+            Creating a Content Provider</a>
+        </li>
+        <li>
+            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
+            Calendar Provider</a>
+        </li>
+    </ol>
+</div>
+</div>
+
+    <!-- Intro paragraphs -->
+<p>
+    A content provider manages access to a central repository of data. The provider and
+    is part of an Android application, which often provides its own UI for working with
+    the data. However, content providers are primarily intended to be used by other
+    applications, which access the provider using a provider client object. Together, providers
+    and provider clients offer a consistent, standard interface to data that also handles
+    inter-process communication and secure data access.
+</p>
+<p>
+    This topic describes the basics of the following:
+</p>
+    <ul>
+        <li>How content providers work.</li>
+        <li>The API you use retrieve data from a content provider.</li>
+        <li>The API you use to insert, update, or delete data in a content provider.</li>
+        <li>Other API features that facilitate working with providers.</li>
+    </ul>
+
+    <!-- Basics -->
+<h2 id="Basics">Overview</h2>
+<p>
+    A content provider presents data to external applications as one or more tables that are
+    similar to the tables found in a relational database. A row represents an instance of some type
+    of data the provider collects, and each row in the column represents an individual piece of
+    data collected for an instance.
+</p>
+<p>
+    For example, one of the built-in providers in the Android platform is the user dictionary, which
+    stores the spellings of non-standard words that the user wants to keep. Table 1 illustrates what
+    the data might look like in this provider's table:
+</p>
+<p class="table-caption">
+    <strong>Table 1:</strong> Sample user dictionary table.
+</p>
+<table id="table1" style="width: 50%;">
+    <tr>
+        <th style="width:20%" align="center" scope="col">word</th>
+        <th style="width:20%" align="center" scope="col">app id</th>
+        <th style="width:20%" align="center" scope="col">frequency</th>
+        <th style="width:20%" align="center" scope="col">locale</th>
+        <th style="width:20%" align="center" scope="col">_ID</th>
+    </tr>
+    <tr>
+        <td align="center" scope="row">mapreduce</td>
+        <td align="center">user1</td>
+        <td align="center">100</td>
+        <td align="center">en_US</td>
+        <td align="center">1</td>
+    </tr>
+    <tr>
+        <td align="center" scope="row">precompiler</td>
+        <td align="center">user14</td>
+        <td align="center">200</td>
+        <td align="center">fr_FR</td>
+        <td align="center">2</td>
+    </tr>
+    <tr>
+        <td align="center" scope="row">applet</td>
+        <td align="center">user2</td>
+        <td align="center">225</td>
+        <td align="center">fr_CA</td>
+        <td align="center">3</td>
+    </tr>
+    <tr>
+        <td align="center" scope="row">const</td>
+        <td align="center">user1</td>
+        <td align="center">255</td>
+        <td align="center">pt_BR</td>
+        <td align="center">4</td>
+    </tr>
+    <tr>
+        <td align="center" scope="row">int</td>
+        <td align="center">user5</td>
+        <td align="center">100</td>
+        <td align="center">en_UK</td>
+        <td align="center">5</td>
+    </tr>
+</table>
+<p>
+    In table 1, each row represents an instance of a word that might not be
+    found in a standard dictionary. Each column represents some data for that word, such as the
+    locale in which it was first encountered. The column headers are column names that are stored in
+    the provider. To refer to a row's locale, you refer to its <code>locale</code> column. For
+    this provider, the <code>_ID</code> column serves as a "primary key" column that
+    the provider automatically maintains.
+</p>
+<p class="note">
+    <strong>Note:</strong> A provider isn't required to have a primary key, and it isn't required
+    to use <code>_ID</code> as the column name of a primary key if one is present. However,
+    if you want to bind data from a provider to a {@link android.widget.ListView}, one of the
+    column names has to be <code>_ID</code>. This requirement is explained in more detail in the
+    section <a href="#DisplayResults">Displaying query results</a>.
+</p>
+<h3 id="ClientProvider">Accessing a provider</h3>
+<p>
+    An application accesses the data from a content provider with
+    a {@link android.content.ContentResolver} client object. This object has methods that call
+    identically-named methods in the provider object, an instance of one of the concrete
+    subclasses of {@link android.content.ContentProvider}. The
+    {@link android.content.ContentResolver} methods provide the basic
+    "CRUD" (create, retrieve, update, and delete) functions of persistent storage.
+</p>
+<p>
+    The {@link android.content.ContentResolver} object in the client application's
+    process and the {@link android.content.ContentProvider} object in the application that owns
+    the provider automatically handle inter-process communication.
+    {@link android.content.ContentProvider} also acts as an abstraction layer between its
+    repository of data and the external appearance of data as tables.
+</p>
+<p class="note">
+    <strong>Note:</strong> To access a provider, your application usually has to request specific
+    permissions in its manifest file. This is described in more detail in the section
+    <a href="#Permissions">Content Provider Permissions</a>
+</p>
+<p>
+    For example, to get a list of the words and their locales from the User Dictionary Provider,
+    you call {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+    ContentResolver.query()}.
+    The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+    query()} method calls the
+    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+    ContentProvider.query()} method defined by the User Dictionary Provider. The following lines
+    of code show a
+    {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+    ContentResolver.query()} call:
+<p>
+<pre>
+// Queries the user dictionary and returns results
+mCursor = getContentResolver().query(
+    UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
+    mProjection,                        // The columns to return for each row
+    mSelectionClause                    // Selection criteria
+    mSelectionArgs,                     // Selection criteria
+    mSortOrder);                        // The sort order for the returned rows
+</pre>
+<p>
+    Table 2 shows how the arguments to
+    {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+    query(Uri,projection,selection,selectionArgs,sortOrder)} match an SQL SELECT statement:
+</p>
+<p class="table-caption">
+    <strong>Table 2:</strong> Query() compared to SQL query.
+</p>
+<table id="table2" style="width: 75%;">
+    <tr>
+        <th style="width:25%" align="center" scope="col">query() argument</th>
+        <th style="width:25%" align="center" scope="col">SELECT keyword/parameter</th>
+        <th style="width:50%" align="center" scope="col">Notes</th>
+    </tr>
+    <tr>
+        <td align="center"><code>Uri</code></td>
+        <td align="center"><code>FROM <em>table_name</em></code></td>
+        <td><code>Uri</code> maps to the table in the provider named <em>table_name</em>.</td>
+    </tr>
+    <tr>
+        <td align="center"><code>projection</code></td>
+        <td align="center"><code><em>col,col,col,...</em></code></td>
+        <td>
+            <code>projection</code> is an array of columns that should be included for each row
+            retrieved.
+        </td>
+    </tr>
+    <tr>
+        <td align="center"><code>selection</code></td>
+        <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td>
+        <td><code>selection</code> specifies the criteria for selecting rows.</td>
+    </tr>
+    <tr>
+        <td align="center"><code>selectionArgs</code></td>
+        <td align="center">
+            (No exact equivalent. Selection arguments replace <code>?</code> placeholders in the
+            selection clause.)
+        </td>
+    </tr>
+    <tr>
+        <td align="center"><code>sortOrder</code></td>
+        <td align="center"><code>ORDER BY <em>col,col,...</em></code></td>
+        <td>
+            <code>sortOrder</code> specifies the order in which rows appear in the returned
+            {@link android.database.Cursor}.
+        </td>
+    </tr>
+</table>
+<h3 id="ContentURIs">Content URIs</h3>
+<p>
+    A <strong>content URI</strong> is a URI that identifies data in a provider. Content URIs
+    include the symbolic name of the entire provider (its <strong>authority</strong>) and a
+    name that points to a table (a <strong>path</strong>). When you call
+    a client method to access a table in a provider, the content URI for the table is one of
+    the arguments.
+</p>
+<p>
+    In the preceding lines of code, the constant
+    {@link android.provider.UserDictionary.Words#CONTENT_URI} contains the content URI of
+    the user dictionary's "words" table. The {@link android.content.ContentResolver}
+    object parses out the URI's authority, and uses it to "resolve" the provider by
+    comparing the authority to a system table of known providers. The
+    {@link android.content.ContentResolver} can then dispatch the query arguments to the correct
+    provider.
+</p>
+<p>
+    The {@link android.content.ContentProvider} uses the path part of the content URI to choose the
+    table to access. A provider usually has a <strong>path</strong> for each table it exposes.
+</p>
+<p>
+    In the previous lines of code, the full URI for the "words" table is:
+</p>
+<pre>
+content://user_dictionary/words
+</pre>
+<p>
+    where the <code>user_dictionary</code> string is the provider's authority, and
+    <code>words</code> string is the table's path. The string
+    <code>content://</code> (the <strong>scheme</strong>) is always present,
+    and identifies this as a content URI.
+</p>
+<p>
+    Many providers allow you to access a single row in a table by appending an ID value
+    to the end of the URI. For example, to retrieve a row whose <code>_ID</code> is
+    <code>4</code> from user dictionary, you can use this content URI:
+</p>
+<pre>
+Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
+</pre>
+<p>
+    You often use id values when you've retrieved a set of rows and then want to update or delete
+    one of them.
+</p>
+<p class="note">
+    <strong>Note:</strong> The {@link android.net.Uri} and {@link android.net.Uri.Builder} classes
+    contain convenience methods for constructing well-formed Uri objects from strings. The
+    {@link android.content.ContentUris} contains convenience methods for appending id values to
+    a URI. The previous snippet uses {@link android.content.ContentUris#withAppendedId(Uri, long)
+    withAppendedId()} to append an id to the UserDictionary content URI.
+</p>
+
+
+    <!-- Retrieving Data from the Provider -->
+<h2 id="SimpleQuery">Retrieving Data from the Provider</h2>
+<p>
+    This section describes how to retrieve data from a provider, using the User Dictionary Provider
+    as an example.
+</p>
+<p class="note">
+    For the sake of clarity, the code snippets in this section call
+    {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+    ContentResolver.query()} on the "UI thread"". In actual code, however, you should
+    do queries asynchronously on a separate thread. One way to do this is to use the
+    {@link android.content.CursorLoader} class, which is described
+    in more detail in the <a href="{@docRoot}guide/topics/fundamentals/loaders.html">
+    Loaders</a> guide. Also, the lines of code are snippets only; they don't show a complete
+    application.
+</p>
+<p>
+    To retrieve data from a provider, follow these basic steps:
+</p>
+<ol>
+   <li>
+        Request the read access permission for the provider.
+   </li>
+   <li>
+        Define the code that sends a query to the provider.
+   </li>
+</ol>
+<h3 id="RequestPermissions">Requesting read access permission</h3>
+<p>
+    To retrieve data from a provider, your application needs "read access permission" for the
+    provider. You can't request this permission at run-time; instead, you have to specify that
+    you need this permission in your manifest, using the
+    <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+    &lt;uses-permission&gt;</a></code> element and the exact permission name defined by the
+    provider. When you specify this element in your manifest, you are in effect "requesting" this
+    permission for your application. When users install your application, they implicitly grant
+    this request.
+</p>
+<p>
+    To find the exact name of the read access permission for the provider you're using, as well
+    as the names for other access permissions used by the provider, look in the provider's
+    documentation.
+</p>
+<p>
+    The role of permissions in accessing providers is described in more detail in the section
+    <a href="#Permissions">Content Provider Permissions</a>.
+</p>
+<p>
+    The User Dictionary Provider defines the permission
+    <code>android.permission.READ_USER_DICTIONARY</code> in its manifest file, so an
+    application that wants to read from the provider must request this permission.
+</p>
+<!-- Constructing the query -->
+<h3 id="Query">Constructing the query</h3>
+<p>
+    The next step in retrieving data a provider is to construct a query. This first snippet
+    defines some variables for accessing the User Dictionary Provider:
+</p>
+<pre class="prettyprint">
+
+// A "projection" defines the columns that will be returned for each row
+String[] mProjection =
+{
+    UserDictionary.Words._ID,    // Contract class constant for the _ID column name
+    UserDictionary.Words.WORD,   // Contract class constant for the word column name
+    UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
+};
+
+// Defines a string to contain the selection clause
+String mSelectionClause = null;
+
+// Initializes an array to contain selection arguments
+String[] mSelectionArgs = {""};
+
+</pre>
+<p>
+    The next snippet shows how to use
+    {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+    ContentResolver.query()}, using the User Dictionary Provider as an example.
+    A provider client query is similar to an SQL query, and it contains a set of columns to return,
+    a set of selection criteria, and a sort order.
+</p>
+<p>
+    The set of columns that the query should return is called a <strong>projection</strong>
+    (the variable <code>mProjection</code>).
+</p>
+<p>
+    The expression that specifies the rows to retrieve is split into a selection clause and
+    selection arguments. The selection clause is a combination of logical and Boolean expressions,
+    column names, and values (the variable <code>mSelection</code>). If you specify the replaceable
+    parameter <code>?</code> instead of a value, the query method retrieves the value from the
+    selection arguments array (the variable <code>mSelectionArgs</code>).
+</p>
+<p>
+    In the next snippet, if the user doesn't enter a word, the selection clause is set to
+    <code>null</code>, and the query returns all the words in the provider. If the user enters
+    a word, the selection clause is set to <code>UserDictionary.Words.Word + " = ?"</code> and
+    the first element of selection arguments array is set to the word the user enters.
+</p>
+<pre class="prettyprint">
+/*
+ * This defines a one-element String array to contain the selection argument.
+ */
+String[] mSelectionArgs = {""};
+
+// Gets a word from the UI
+mSearchString = mSearchWord.getText().toString();
+
+// Remember to insert code here to check for invalid or malicious input.
+
+// If the word is the empty string, gets everything
+if (TextUtils.isEmpty(mSearchString)) {
+    // Setting the selection clause to null will return all words
+    mSelectionClause = null;
+    mSelectionArgs[0] = "";
+
+} else {
+    // Constructs a selection clause that matches the word that the user entered.
+    mSelectionClause = " = ?";
+
+    // Moves the user's input string to the selection arguments.
+    mSelectionArgs[0] = mSearchString;
+
+}
+
+// Does a query against the table and returns a Cursor object
+mCursor = getContentResolver().query(
+    UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
+    mProjection,                       // The columns to return for each row
+    mSelectionClause                   // Either null, or the word the user entered
+    mSelectionArgs,                    // Either empty, or the string the user entered
+    mSortOrder);                       // The sort order for the returned rows
+
+// Some providers return null if an error occurs, others throw an exception
+if (null == mCursor) {
+    /*
+     * Insert code here to handle the error. Be sure not to use the cursor! You may want to
+     * call android.util.Log.e() to log this error.
+     *
+     */
+// If the Cursor is empty, the provider found no matches
+} else if (mCursor.getCount() &lt; 1) {
+
+    /*
+     * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily
+     * an error. You may want to offer the user the option to insert a new row, or re-type the
+     * search term.
+     */
+
+} else {
+    // Insert code here to do something with the results
+
+}
+</pre>
+<p>
+    This query is analogous to the SQL statement:
+</p>
+<pre>
+SELECT _ID, word, frequency, locale FROM words WHERE word = &lt;userinput&gt; ORDER BY word ASC;
+</pre>
+<p>
+    In this SQL statement, the actual column names are used instead of contract class constants.
+</p>
+<h4 id="Injection">Protecting against malicious input</h4>
+<p>
+    If the data managed by the content provider is in an SQL database, including external untrusted
+    data into raw SQL statements can lead to SQL injection.
+</p>
+<p>
+    Consider this selection clause:
+</p>
+<pre>
+// Constructs a selection clause by concatenating the user's input to the column name
+String mSelectionClause =  "var = " + mUserInput;
+</pre>
+<p>
+    If you do this, you're allowing the user to concatenate malicious SQL onto your SQL statement.
+    For example, the user could enter "nothing; DROP TABLE *;"  for <code>mUserInput</code>, which
+    would result in the selection clause <code>var = nothing; DROP TABLE *;</code>. Since the
+    selection clause is treated as an SQL statement, this might cause the provider to erase all of
+    the tables in the underlying SQLite database (unless the provider is set up to catch
+    <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL injection</a> attempts).
+</p>
+<p>
+    To avoid this problem, use a selection clause that uses <code>?</code> as a replaceable
+    parameter and a separate array of selection arguments. When you do this, the user input
+    is bound directly to the query rather than being interpreted as part of an SQL statement.
+    Because it's not treated as SQL, the user input can't inject malicious SQL. Instead of using
+    concatenation to include the user input, use this selection clause:
+</p>
+<pre>
+// Constructs a selection clause with a replaceable parameter
+String mSelectionClause =  "var = ?";
+</pre>
+<p>
+    Set up the array of selection arguments like this:
+</p>
+<pre>
+// Defines an array to contain the selection arguments
+String[] selectionArgs = {""};
+</pre>
+<p>
+    Put a value in the selection arguments array like this:
+</p>
+<pre>
+// Sets the selection argument to the user's input
+selectionArgs[0] = mUserInput;
+</pre>
+<p>
+    A selection clause that uses <code>?</code> as a replaceable parameter and an array of
+    selection arguments array are preferred way to specify a selection, even the provider isn't
+    based on an SQL database.
+</p>
+<!-- Displaying the results -->
+<h3 id="DisplayResults">Displaying query results</h3>
+<p>
+    The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+    ContentResolver.query()} client method always returns a {@link android.database.Cursor}
+    containing the columns specified by the query's projection for the rows that match the query's
+    selection criteria. A {@link android.database.Cursor} object provides random read access to the
+    rows and columns it contains. Using {@link android.database.Cursor} methods,
+    you can iterate over the rows in the results, determine the data type of each column, get the
+    data out of a column, and examine other properties of the results. Some
+    {@link android.database.Cursor} implementations automatically update the object when the
+    provider's data changes, or trigger methods in an observer object when the
+    {@link android.database.Cursor} changes, or both.
+</p>
+<p class="note">
+    <strong>Note:</strong> A provider may restrict access to columns based on the nature of the
+    object making the query. For example, the Contacts Provider restricts access for some columns to
+    sync adapters, so it won't return them to an activity or service.
+</p>
+<p>
+    If no rows match the selection criteria, the provider
+    returns a {@link android.database.Cursor} object for which
+    {@link android.database.Cursor#getCount() Cursor.getCount()} is 0 (an empty cursor).
+</p>
+<p>
+    If an internal error occurs, the results of the query depend on the particular provider. It may
+    choose to return <code>null</code>, or it may throw an {@link java.lang.Exception}.
+</p>
+<p>
+    Since a {@link android.database.Cursor} is a "list" of rows, a good way to display the
+    contents of a {@link android.database.Cursor} is to link it to a {@link android.widget.ListView}
+    via a {@link android.widget.SimpleCursorAdapter}.
+</p>
+<p>
+    The following snippet continues the code from the previous snippet. It creates a
+    {@link android.widget.SimpleCursorAdapter} object containing the {@link android.database.Cursor}
+    retrieved by the query, and sets this object to be the adapter for a
+    {@link android.widget.ListView}:
+</p>
+<pre class="prettyprint">
+// Defines a list of columns to retrieve from the Cursor and load into an output row
+String[] mWordListColumns =
+{
+    UserDictionary.Words.WORD,   // Contract class constant containing the word column name
+    UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
+};
+
+// Defines a list of View IDs that will receive the Cursor columns for each row
+int[] mWordListItems = { R.id.dictWord, R.id.locale};
+
+// Creates a new SimpleCursorAdapter
+mCursorAdapter = new SimpleCursorAdapter(
+    getApplicationContext(),               // The application's Context object
+    R.layout.wordlistrow,                  // A layout in XML for one row in the ListView
+    mCursor,                               // The result from the query
+    mWordListColumns,                      // A string array of column names in the cursor
+    mWordListItems,                        // An integer array of view IDs in the row layout
+    0);                                    // Flags (usually none are needed)
+
+// Sets the adapter for the ListView
+mWordList.setAdapter(mCursorAdapter);
+</pre>
+<p class="note">
+    <strong>Note:</strong> To back a {@link android.widget.ListView} with a
+    {@link android.database.Cursor}, the cursor must contain a column named <code>_ID</code>.
+    Because of this, the query shown previously retrieves the <code>_ID</code> column for the
+    "words" table, even though the {@link android.widget.ListView} doesn't display it.
+    This restriction also explains why most providers have a <code>_ID</code> column for each of
+    their tables.
+</p>
+
+        <!-- Getting data from query results -->
+<h3 id="GettingResults">Getting data from query results</h3>
+<p>
+    Rather than simply displaying query results, you can use them for other tasks. For
+    example, you can retrieve spellings from the user dictionary and then look them up in
+    other providers. To do this, you iterate over the rows in the {@link android.database.Cursor}:
+</p>
+<pre class="prettyprint">
+
+// Determine the column index of the column named "word"
+int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);
+
+/*
+ * Only executes if the cursor is valid. The User Dictionary Provider returns null if
+ * an internal error occurs. Other providers may throw an Exception instead of returning null.
+ */
+
+if (mCursor != null) {
+    /*
+     * Moves to the next row in the cursor. Before the first movement in the cursor, the
+     * "row pointer" is -1, and if you try to retrieve data at that position you will get an
+     * exception.
+     */
+    while (mCursor.moveToNext()) {
+
+        // Gets the value from the column.
+        newWord = mCursor.getString(index);
+
+        // Insert code here to process the retrieved word.
+
+        ...
+
+        // end of while loop
+    }
+} else {
+
+    // Insert code here to report an error if the cursor is null or the provider threw an exception.
+}
+</pre>
+<p>
+    {@link android.database.Cursor} implementations contain several "get" methods for
+    retrieving different types of data from the object. For example, the previous snippet
+    uses {@link android.database.Cursor#getString(int) getString()}. They also have a
+    {@link android.database.Cursor#getType(int) getType()} method that returns a value indicating
+    the data type of the column.
+</p>
+
+
+    <!-- Requesting permissions -->
+<h2 id="Permissions">Content Provider Permissions</h2>
+<p>
+    A provider's application can specify permissions that other applications must have in order to
+    access the provider's data. These permissions ensure that the user knows what data
+    an application will try to access. Based on the provider's requirements, other applications
+    request the permissions they need in order to access the provider. End users see the requested
+    permissions when they install the application.
+</p>
+<p>
+    If a provider's application doesn't specify any permissions, then other applications have no
+    access to the provider's data. However, components in the provider's application always have
+    full read and write access, regardless of the specified permissions.
+</p>
+<p>
+    As noted previously, the User Dictionary Provider requires the
+    <code>android.permission.READ_USER_DICTIONARY</code> permission to retrieve data from it.
+    The provider has the separate <code>android.permission.WRITE_USER_DICTIONARY</code>
+    permission for inserting, updating, or deleting data.
+</p>
+<p>
+    To get the permissions needed to access a provider, an application requests them with a
+    <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+    &lt;uses-permission&gt;</a></code> element in its manifest file.
+    When the Android Package Manager installs the application, a user must approve all of the
+    permissions the application requests. If the user approves all of them, Package Manager
+    continues the installation; if the user doesn't approve them, Package Manager
+    aborts the installation.
+</p>
+<p>
+    The following
+    <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+    &lt;uses-permission&gt;</a></code> element requests read access to the User Dictionary Provider:
+</p>
+<pre>
+    &lt;uses-permission android:name="android.permission.READ_USER_DICTIONARY"&gt;
+</pre>
+<p>
+    The impact of permissions on provider access is explained in more detail in the
+    <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> guide.
+</p>
+
+
+<!-- Inserting, Updating, and Deleting Data -->
+<h2 id="Modifications">Inserting, Updating, and Deleting Data</h2>
+<p>
+    In the same way that you retrieve data from a provider, you also use the interaction between
+    a provider client and the provider's {@link android.content.ContentProvider} to modify data.
+    You call a method of {@link android.content.ContentResolver} with arguments that are passed to
+    the corresponding method of {@link android.content.ContentProvider}. The provider and provider
+    client automatically handle security and inter-process communication.
+</p>
+<h3 id="Inserting">Inserting data</h3>
+<p>
+    To insert data into a provider, you call the
+    {@link android.content.ContentResolver#insert(Uri,ContentValues) ContentResolver.insert()}
+    method. This method inserts a new row into the provider and returns a content URI for that row.
+    This snippet shows how to insert a new word into the User Dictionary Provider:
+</p>
+<pre class="prettyprint">
+// Defines a new Uri object that receives the result of the insertion
+Uri mNewUri;
+
+...
+
+// Defines an object to contain the new values to insert
+ContentValues mNewValues = new ContentValues();
+
+/*
+ * Sets the values of each column and inserts the word. The arguments to the "put"
+ * method are "column name" and "value"
+ */
+mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
+mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
+mNewValues.put(UserDictionary.Words.WORD, "insert");
+mNewValues.put(UserDictionary.Words.FREQUENCY, "100");
+
+mNewUri = getContentResolver().insert(
+    UserDictionary.Word.CONTENT_URI,   // the user dictionary content URI
+    mNewValues                          // the values to insert
+);
+</pre>
+<p>
+    The data for the new row goes into a single {@link android.content.ContentValues} object, which
+    is similar in form to a one-row cursor. The columns in this object don't need to have the
+    same data type, and if you don't want to specify a value at all, you can set a column
+    to <code>null</code> using {@link android.content.ContentValues#putNull(String)
+    ContentValues.putNull()}.
+</p>
+<p>
+    The snippet doesn't add the <code>_ID</code> column, because this column is maintained
+    automatically. The provider assigns a unique value of <code>_ID</code> to every row that is
+    added. Providers usually use this value as the table's primary key.
+</p>
+<p>
+    The content URI returned in <code>newUri</code> identifies the newly-added row, with
+    the following format:
+</p>
+<pre>
+content://user_dictionary/words/&lt;id_value&gt;
+</pre>
+<p>
+    The <code>&lt;id_value&gt;</code> is the contents of <code>_ID</code> for the new row.
+    Most providers can detect this form of content URI automatically and then perform the requested
+    operation on that particular row.
+</p>
+<p>
+    To get the value of <code>_ID</code> from the returned {@link android.net.Uri}, call
+    {@link android.content.ContentUris#parseId(Uri) ContentUris.parseId()}.
+</p>
+<h3 id="Updating">Updating data</h3>
+<p>
+    To update a row, you use a {@link android.content.ContentValues} object with the updated
+    values just as you do with an insertion, and selection criteria just as you do with a query.
+    The client method you use is
+    {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[])
+    ContentResolver.update()}. You only need to add values to the
+    {@link android.content.ContentValues} object for columns you're updating. If you want to clear
+    the contents of a column, set the value to <code>null</code>.
+</p>
+<p>
+    The following snippet changes all the rows whose locale has the language "en" to a
+    have a locale of <code>null</code>. The return value is the number of rows that were updated:
+</p>
+<pre>
+// Defines an object to contain the updated values
+ContentValues mUpdateValues = new ContentValues();
+
+// Defines selection criteria for the rows you want to update
+String mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";
+String[] mSelectionArgs = {"en_%"};
+
+// Defines a variable to contain the number of updated rows
+int mRowsUpdated = 0;
+
+...
+
+/*
+ * Sets the updated value and updates the selected words.
+ */
+mUpdateValues.putNull(UserDictionary.Words.LOCALE);
+
+mRowsUpdated = getContentResolver().update(
+    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
+    mUpdateValues                       // the columns to update
+    mSelectionClause                    // the column to select on
+    mSelectionArgs                      // the value to compare to
+);
+</pre>
+<p>
+    You should also sanitize user input when you call
+    {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[])
+    ContentResolver.update()}. To learn more about this, read the section
+    <a href="#Injection">Protecting against malicious input</a>.
+</p>
+<h3 id="Deleting">Deleting data</h3>
+<p>
+    Deleting rows is similar to retrieving row data: you specify selection criteria for the rows
+    you want to delete and the client method returns the number of deleted rows.
+    The following snippet deletes rows whose appid matches "user". The method returns the
+    number of deleted rows.
+</p>
+<pre>
+
+// Defines selection criteria for the rows you want to delete
+String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
+String[] mSelectionArgs = {"user"};
+
+// Defines a variable to contain the number of rows deleted
+int mRowsDeleted = 0;
+
+...
+
+// Deletes the words that match the selection criteria
+mRowsDeleted = getContentResolver().delete(
+    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
+    mSelectionClause                    // the column to select on
+    mSelectionArgs                      // the value to compare to
+);
+</pre>
+<p>
+    You should also sanitize user input when you call
+    {@link android.content.ContentResolver#delete(Uri, String, String[])
+    ContentResolver.delete()}. To learn more about this, read the section
+    <a href="#Injection">Protecting against malicious input</a>.
+</p>
+<!-- Provider Data Types -->
+<h2 id="DataTypes">Provider Data Types</h2>
+<p>
+    Content providers can offer many different data types. The User Dictionary Provider offers only
+    text, but providers can also offer the following formats:
+</p>
+    <ul>
+        <li>
+            integer
+        </li>
+        <li>
+            long integer (long)
+        </li>
+        <li>
+            floating point
+        </li>
+        <li>
+            long floating point (double)
+        </li>
+    </ul>
+<p>
+    Another data type that providers often use is Binary Large OBject (BLOB) implemented as a
+    64KB byte array. You can see the available data types by looking at the
+    {@link android.database.Cursor} class "get" methods.
+</p>
+<p>
+    The data type for each column in a provider is usually listed in its documentation.
+    The data types for the User Dictionary Provider are listed in the reference documentation
+    for its contract class {@link android.provider.UserDictionary.Words} (contract classes are
+    described in the section <a href="#ContractClasses">Contract Classes</a>).
+    You can also determine the data type by calling {@link android.database.Cursor#getType(int)
+    Cursor.getType()}.
+</p>
+<p>
+    Providers also maintain MIME data type information for each content URI they define. You can
+    use the MIME type information to find out if your application can handle data that the
+    provider offers, or to choose a type of handling based on the MIME type. You usually need the
+    MIME type when you are working with a provider that contains complex
+    data structures or files. For example, the {@link android.provider.ContactsContract.Data}
+    table in the Contacts Provider uses MIME types to label the type of contact data stored in each
+    row. To get the MIME type corresponding to a content URI, call
+    {@link android.content.ContentResolver#getType(Uri) ContentResolver.getType()}.
+</p>
+<p>
+    The section <a href="#MIMETypeReference">MIME Type Reference</a> describes the
+    syntax of both standard and custom MIME types.
+</p>
+
+
+<!-- Alternative Forms of Provider Access -->
+<h2 id="AltForms">Alternative Forms of Provider Access</h2>
+<p>
+    Three alternative forms of provider access are important in application development:
+</p>
+<ul>
+    <li>
+        <a href="#Batch">Batch access</a>: You can create a batch of access calls with methods in
+        the {@link android.content.ContentProviderOperation} class, and then apply them with
+        {@link android.content.ContentResolver#applyBatch(String, ArrayList)
+        ContentResolver.applyBatch()}.
+    </li>
+    <li>
+        Asynchronous queries: You should do queries in a separate thread. One way to do this is to
+        use a {@link android.content.CursorLoader} object. The examples in the
+        <a href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> guide demonstrate
+        how to do this.
+    </li>
+    <li>
+        <a href="#Intents">Data access via intents</a>: Although you can't send an intent
+        directly to a provider, you can send an intent to the provider's application, which is
+        usually the best-equipped to modify the provider's data.
+    </li>
+</ul>
+<p>
+    Batch access and modification via intents are described in the following sections.
+</p>
+<h3 id="Batch">Batch access</h3>
+<p>
+    Batch access to a provider is useful for inserting a large number of rows, or for inserting
+    rows in multiple tables in the same method call, or in general for performing a set of
+    operations across process boundaries as a transaction (an atomic operation).
+</p>
+<p>
+    To access a provider in "batch mode",
+    you create an array of {@link android.content.ContentProviderOperation} objects and then
+    dispatch them to a content provider with
+    {@link android.content.ContentResolver#applyBatch(String, ArrayList)
+    ContentResolver.applyBatch()}. You pass the content provider's <em>authority</em> to this
+    method, rather than a particular content URI, which allows each
+    {@link android.content.ContentProviderOperation} object in the array to work against a
+    different table. A call to {@link android.content.ContentResolver#applyBatch(String, ArrayList)
+    ContentResolver.applyBatch()} returns an array of results.
+</p>
+<p>
+    The description of the {@link android.provider.ContactsContract.RawContacts} contract class
+    includes a code snippet that demonstrates batch insertion. The
+    <a href="{@docRoot}resources/samples/ContactManager/index.html">Contact Manager</a>
+    sample application contains an example of batch access in its <code>ContactAdder.java</code>
+    source file.
+</p>
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>Displaying data using a helper app</h2>
+<p>
+    If your application <em>does</em> have access permissions, you still may want to use an
+    intent to display data in another application. For example, the Calendar application accepts an
+    {@link android.content.Intent#ACTION_VIEW} intent, which displays a particular date or event.
+    This allows you to display calendar information without having to create your own UI.
+    To learn more about this feature, see the
+    <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a> guide.
+</p>
+<p>
+    The application to which you send the intent doesn't have to be the application
+    associated with the provider. For example, you can retrieve a contact from the
+    Contact Provider, then send an {@link android.content.Intent#ACTION_VIEW} intent
+    containing the content URI for the contact's image to an image viewer.
+</p>
+</div>
+</div>
+<h3 id="Intents">Data access via intents</h3>
+<p>
+    Intents can provide indirect access to a content provider. You allow the user to access
+    data in a provider even if your application doesn't have access permissions, either by
+    getting a result intent back from an application that has permissions, or by activating an
+    application that has permissions and letting the user do work in it.
+</p>
+<h4>Getting access with temporary permissions</h4>
+<p>
+    You can access data in a content provider, even if you don't have the proper access
+    permissions, by sending an intent to an application that does have the permissions and
+    receiving back a result intent containing "URI" permissions.
+    These are permissions for a specific content URI that last until the activity that receives
+    them is finished. The application that has permanent permissions grants temporary
+    permissions by setting a flag in the result intent:
+</p>
+<ul>
+    <li>
+        <strong>Read permission:</strong>
+        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}
+    </li>
+    <li>
+        <strong>Write permission:</strong>
+        {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}
+    </li>
+</ul>
+<p class="note">
+    <strong>Note:</strong> These flags don't give general read or write access to the provider
+    whose authority is contained in the content URI. The access is only for the URI itself.
+</p>
+<p>
+    A provider defines URI permissions for content URIs in its manifest, using the
+    <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+    android:grantUriPermission</a></code>
+    attribute of the
+    {@code <a href="guide/topics/manifest/provider-element.html">&lt;provider&gt;</a>}
+    element, as well as the
+    {@code <a href="guide/topics/manifest/grant-uri-permission-element.html">
+    &lt;grant-uri-permission&gt;</a>} child element of the
+    {@code <a href="guide/topics/manifest/provider-element.html">&lt;provider&gt;</a>}
+    element. The URI permissions mechanism is explained in more detail in the
+    <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> guide,
+    in the section "URI Permissions".
+</p>
+<p>
+    For example, you can retrieve data for a contact in the Contacts Provider, even if you don't
+    have the {@link android.Manifest.permission#READ_CONTACTS} permission. You might want to do
+    this in an application that sends e-greetings to a contact on his or her birthday. Instead of
+    requesting {@link android.Manifest.permission#READ_CONTACTS}, which gives you access to all of
+    the user's contacts and all of their information, you prefer to let the user control which
+    contacts are used by your application. To do this, you use the following process:
+</p>
+<ol>
+    <li>
+        Your application sends an intent containing the action
+        {@link android.content.Intent#ACTION_PICK} and the "contacts" MIME type
+        {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, using the
+        method {@link android.app.Activity#startActivityForResult(Intent, int)
+        startActivityForResult()}.
+    </li>
+    <li>
+        Because this intent matches the intent filter for the
+        People app's "selection" activity, the activity will come to the foreground.
+    </li>
+    <li>
+        In the selection activity, the user selects a
+        contact to update. When this happens, the selection activity calls
+        {@link android.app.Activity#setResult(int, Intent) setResult(resultcode, intent)}
+        to set up a intent to give back to your application. The intent contains the content URI
+        of the contact the user selected, and the "extras" flags
+        {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. These flags grant URI
+        permission to your app to read data for the contact pointed to by the
+        content URI. The selection activity then calls {@link android.app.Activity#finish()} to
+        return control to your application.
+    </li>
+    <li>
+        Your activity returns to the foreground, and the system calls your activity's
+        {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()}
+        method. This method receives the result intent created by the selection activity in
+        the People app.
+    </li>
+    <li>
+        With the content URI from the result intent, you can read the contact's data
+        from the Contacts Provider, even though you didn't request permanent read access permission
+        to the provider in your manifest. You can then get the contact's birthday information
+        or his or her email address and then send the e-greeting.
+    </li>
+</ol>
+<h4>Using another application</h4>
+<p>
+    A simple way to allow the user to modify data to which you don't have access permissions is to
+    activate an application that has permissions and let the user do the work there.
+</p>
+<p>
+    For example, the Calendar application accepts an
+    {@link android.content.Intent#ACTION_INSERT} intent, which allows you to activate the
+    application's insert UI. You can pass "extras" data in this intent, which the application
+    uses to pre-populate the UI. Because recurring events have a complex syntax, the preferred
+    way of inserting events into the Calendar Provider is to activate the Calendar app with an
+    {@link android.content.Intent#ACTION_INSERT} and then let the user insert the event there.
+</p>
+<!-- Contract Classes -->
+<h2 id="ContractClasses">Contract Classes</h2>
+<p>
+    A contract class defines constants that help applications work with the content URIs, column
+    names, intent actions, and other features of a content provider. Contract classes are not
+    included automatically with a provider; the provider's developer has to define them and then
+    make them available to other developers. Many of the providers included with the Android
+    platform have corresponding contract classes in the package {@link android.provider}.
+</p>
+<p>
+    For example, the User Dictionary Provider has a contract class
+    {@link android.provider.UserDictionary} containing content URI and column name constants. The
+    content URI for the "words" table is defined in the constant
+    {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}.
+    The {@link android.provider.UserDictionary.Words} class also contains column name constants,
+    which are used in the example snippets in this guide. For example, a query projection can be
+    defined as:
+</p>
+<pre>
+String[] mProjection =
+{
+    UserDictionary.Words._ID,
+    UserDictionary.Words.WORD,
+    UserDictionary.Words.LOCALE
+};
+</pre>
+<p>
+    Another contract class is {@link android.provider.ContactsContract} for the Contacts Provider.
+    The reference documentation for this class includes example code snippets. One of its
+    subclasses, {@link android.provider.ContactsContract.Intents.Insert}, is a contract
+    class that contains constants for intents and intent data.
+</p>
+
+
+<!-- MIME Type Reference -->
+<h2 id="MIMETypeReference">MIME Type Reference</h2>
+<p>
+    Content providers can return standard MIME media types, or custom MIME type strings, or both.
+</p>
+<p>
+    MIME types have the format
+</p>
+<pre>
+<em>type</em>/<em>subtype</em>
+</pre>
+<p>
+    For example, the well-known MIME type <code>text/html</code> has the <code>text</code> type and
+    the <code>html</code> subtype. If the provider returns this type for a URI, it means that a
+    query using that URI will return text containing HTML tags.
+</p>
+<p>
+    Custom MIME type strings, also called "vendor-specific" MIME types, have more
+    complex <em>type</em> and <em>subtype</em> values. The <em>type</em> value is always
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>
+</pre>
+<p>
+    for multiple rows, or
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>
+</pre>
+<p>
+    for a single row.
+</p>
+<p>
+    The <em>subtype</em> is provider-specific. The Android built-in providers usually have a simple
+    subtype. For example, the when the Contacts application creates a row for a telephone number,
+    it sets the following MIME type in the row:
+</p>
+<pre>
+vnd.android.cursor.item/phone_v2
+</pre>
+<p>
+    Notice that the subtype value is simply <code>phone_v2</code>.
+</p>
+<p>
+    Other provider developers may create their own pattern of subtypes based on the provider's
+    authority and table names. For example, consider a provider that contains train timetables.
+    The provider's authority is <code>com.example.trains</code>, and it contains the tables
+    Line1, Line2, and Line3. In response to the content URI
+</p>
+<p>
+<pre>
+content://com.example.trains/Line1
+</pre>
+<p>
+    for table Line1, the provider returns the MIME type
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>/vnd.example.line1
+</pre>
+<p>
+     In response to the content URI
+</p>
+<pre>
+content://com.example.trains/Line2/5
+</pre>
+<p>
+    for row 5 in table Line2, the provider returns the MIME type
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>/vnd.example.line2
+</pre>
+<p>
+    Most content providers define contract class constants for the MIME types they use. The
+    Contacts Provider contract class {@link android.provider.ContactsContract.RawContacts},
+    for example, defines the constant
+    {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} for the MIME type of
+    a single raw contact row.
+</p>
+<p>
+    Content URIs for single rows are described in the section
+    <a href="#ContentURIs">Content URIs</a>.
+</p>
diff --git a/docs/html/guide/topics/providers/content-provider-creating.jd b/docs/html/guide/topics/providers/content-provider-creating.jd
new file mode 100644
index 0000000..4ebdb50
--- /dev/null
+++ b/docs/html/guide/topics/providers/content-provider-creating.jd
@@ -0,0 +1,1215 @@
+page.title=Creating a Content Provider
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+
+
+<h2>In this document</h2>
+<ol>
+    <li>
+        <a href="#DataStorage">Designing Data Storage</a>
+    </li>
+    <li>
+        <a href="#ContentURI">Designing Content URIs</a>
+    </li>
+    <li>
+        <a href="#ContentProvider">Implementing the ContentProvider Class</a>
+        <ol>
+            <li>
+                <a href="#RequiredAccess">Required Methods</a>
+            </li>
+            <li>
+                <a href="#Query">Implementing the query() method</a>
+            </li>
+            <li>
+                <a href="#Insert">Implementing the insert() method</a>
+            </li>
+            <li>
+                <a href="#Delete">Implementing the delete() method</a>
+            </li>
+            <li>
+                <a href="#Update">Implementing the update() method</a>
+            </li>
+            <li>
+                <a href="#OnCreate">Implementing the onCreate() method</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#MIMETypes">Implementing Content Provider MIME Types</a>
+        <ol>
+            <li>
+                <a href="#TableMIMETypes">MIME types for tables</a>
+            </li>
+            <li>
+                <a href="#FileMIMETypes">MIME types for files</a>
+            </li>
+        </ol>
+    </li>
+    <li>
+        <a href="#ContractClass">Implementing a Contract Class</a>
+    </li>
+    <li>
+        <a href="#Permissions">Implementing Content Provider Permissions</a>
+    </li>
+    <li>
+        <a href="#ProviderElement">The &lt;provider&gt; Element</a>
+    </li>
+    <li>
+        <a href="#Intents">Intents and Data Access</a>
+    </li>
+</ol>
+<h2>Key classes</h2>
+    <ol>
+        <li>
+            {@link android.content.ContentProvider}
+        </li>
+        <li>
+            {@link android.database.Cursor}
+        </li>
+        <li>
+            {@link android.net.Uri}
+        </li>
+    </ol>
+<h2>Related Samples</h2>
+    <ol>
+        <li>
+            <a
+                href="{@docRoot}resources/samples/NotePad/index.html">
+                Note Pad sample application
+            </a>
+        </li>
+    </ol>
+<h2>See also</h2>
+    <ol>
+        <li>
+            <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+            Content Provider Basics</a>
+        </li>
+        <li>
+            <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
+            Calendar Provider</a>
+        </li>
+    </ol>
+</div>
+</div>
+
+
+<p>
+    A content provider manages access to a central repository of data. You implement a
+    provider as one or more classes in an Android application, along with elements in
+    the manifest file. One of your classes implements a subclass
+    {@link android.content.ContentProvider}, which is the interface between your provider and
+    other applications. Although content providers are meant to make data available to other
+    applications, you may of course have activities in your application that allow the user
+    to query and modify the data managed by your provider.
+</p>
+<p>
+    The rest of this topic is a basic list of steps for building a content provider and a list
+    of APIs to use.
+</p>
+
+
+<!-- Before You Start Building -->
+<h2 id="BeforeYouStart">Before You Start Building</h2>
+<p>
+    Before you start building a provider, do the following:
+</p>
+<ol>
+    <li>
+        <strong>Decide if you need a content provider</strong>. You need to build a content
+        provider if you want to provide one or more of the following features:
+        <ul>
+            <li>You want to offer complex data or files to other applications.</li>
+            <li>You want to allow users to copy complex data from your app into other apps.</li>
+            <li>You want to provide custom search suggestions using the search framework.</li>
+        </ul>
+    <p>
+        You <em>don't</em> need a provider to use an SQLite database if the use is entirely within
+        your own application.
+    </p>
+    </li>
+    <li>
+        If you haven't done so already, read the topic
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Content Provider Basics</a> to learn more about providers.
+    </li>
+</ol>
+<p>
+    Next, follow these steps to build your provider:
+</p>
+<ol>
+    <li>
+        Design the raw storage for your data. A content provider offers data in two ways:
+        <dl>
+            <dt>
+                File data
+            </dt>
+            <dd>
+                Data that normally goes into files, such as
+                photos, audio, or videos. Store the files in your application's private
+                space. In response to a request for a file from another application, your
+                provider can offer a handle to the file.
+            </dd>
+            <dt>
+                &quot;Structured&quot; data
+            </dt>
+            <dd>
+                Data that normally goes into a database, array, or similar structure.
+                Store the data in a form that's compatible with tables of rows and columns. A row
+                represents an entity, such as a person or an item in inventory. A column represents
+                some data for the entity, such a person's name or an item's price. A common way to
+                store this type of data is in an SQLite database, but you can use any type of
+                persistent storage. To learn more about the storage types available in the
+                Android system, see the section <a href="#DataStorage">
+                Designing Data Storage</a>.
+            </dd>
+        </dl>
+    </li>
+    <li>
+        Define a concrete implementation of the {@link android.content.ContentProvider} class and
+        its required methods. This class is the interface between your data and the rest of the
+        Android system. For more information about this class, see the section
+        <a href="#ContentProvider">Implementing the ContentProvider Class</a>.
+    </li>
+    <li>
+        Define the provider's authority string, its content URIs, and column names. If you want
+        the provider's application to handle intents, also define intent actions, extras data,
+        and flags. Also define the permissions that you will require for applications that want
+        to access your data. You should consider defining all of these values as constants in a
+        separate contract class; later, you can expose this class to other developers. For more
+        information about content URIs, see the
+        section <a href="#ContentURI">Designing Content URIs</a>.
+        For more information about intents, see the
+        section <a href="#Intents">Intents and Data Access</a>.
+    </li>
+    <li>
+        Add other optional pieces, such as sample data or an implementation
+        of {@link android.content.AbstractThreadedSyncAdapter} that can synchronize data between
+        the provider and cloud-based data.
+    </li>
+</ol>
+
+
+<!-- Designing Data Storage -->
+<h2 id="DataStorage">Designing Data Storage</h2>
+<p>
+    A content provider is the interface to data saved in a structured format. Before you create
+    the interface, you must decide how to store the data. You can store the data in any form you
+    like, and then design the interface to read and write the data as necessary.
+</p>
+<p>
+    These are some of the data storage technologies that are available in Android:
+</p>
+<ul>
+    <li>
+        The Android system includes an SQLite database API that Android's own providers use
+        to store table-oriented data. The
+        {@link android.database.sqlite.SQLiteOpenHelper} class helps you create databases, and the
+        {@link android.database.sqlite.SQLiteDatabase} class is the base class for accessing
+        databases.
+        <p>
+            Remember that you don't have to use a database to implement your repository. A provider
+            appears externally as a set of tables, similar to a relational database, but this is
+            not a requirement for the provider's internal implementation.
+        </p>
+    </li>
+    <li>
+        For storing file data, Android has a variety of file-oriented APIs.
+        To learn more about file storage, read the topic
+        <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>. If you're
+        designing a provider that offers media-related data such as music or videos, you can
+        have a provider that combines table data and files.
+    </li>
+    <li>
+        For working with network-based data, use classes in {@link java.net} and
+        {@link android.net}. You can also synchronize network-based data to a local data
+        store such as a database, and then offer the data as tables or files.
+        The <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
+        Sample Sync Adapter</a> sample application demonstrates this type of synchronization.
+    </li>
+</ul>
+<h3 id="DataDesign">
+    Data design considerations
+</h3>
+<p>
+    Here are some tips for designing your provider's data structure:
+</p>
+<ul>
+    <li>
+        Table data should always have a &quot;primary key&quot; column that the provider maintains
+        as a unique numeric value for each row. You can use this value to link the row to related
+        rows in other tables (using it as a &quot;foreign key&quot;). Although you can use any name
+        for this column, using {@link android.provider.BaseColumns#_ID BaseColumns._ID} is the best
+        choice, because linking the results of a provider query to a
+        {@link android.widget.ListView} requires one of the retrieved columns to have the name
+        <code>_ID</code>.
+    </li>
+    <li>
+        If you want to provide bitmap images or other very large pieces of file-oriented data, store
+        the data in a file and then provide it indirectly rather than storing it directly in a
+        table. If you do this, you need to tell users of your provider that they need to use a
+        {@link android.content.ContentResolver} file method to access the data.
+    </li>
+    <li>
+        Use the Binary Large OBject (BLOB) data type to store data that varies in size or has a
+        varying structure. For example, you can use a BLOB column to store a
+        <a href="http://code.google.com/p/protobuf">protocol buffer</a> or
+        <a href="http://www.json.org">JSON structure</a>.
+        <p>
+            You can also use a BLOB to implement a <em>schema-independent</em> table. In
+            this type of table, you define a primary key column, a MIME type column, and one or
+            more generic columns as BLOB. The meaning of the data in the BLOB columns is indicated
+            by the value in the MIME type column. This allows you to store different row types in
+            the same table. The Contacts Provider's &quot;data&quot; table
+            {@link android.provider.ContactsContract.Data} is an example of a schema-independent
+            table.
+        </p>
+    </li>
+</ul>
+<!-- Designing Content URIs -->
+<h2 id="ContentURI">Designing Content URIs</h2>
+<p>
+    A <strong>content URI</strong> is a URI that identifies data in a provider. Content URIs include
+    the symbolic name of the entire provider (its <strong>authority</strong>) and a
+    name that points to a table or file (a <strong>path</strong>). The optional id part points to
+    an individual row in a table. Every data access method of
+    {@link android.content.ContentProvider} has a content URI as an argument; this allows you to
+    determine the table, row, or file to access.
+</p>
+<p>
+    The basics of content URIs are described in the topic
+    <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+    Content Provider Basics</a>.
+</p>
+<h3>Designing an authority</h3>
+<p>
+    A provider usually has a single authority, which serves as its Android-internal name. To
+    avoid conflicts with other providers, you should use Internet domain ownership (in reverse)
+    as the basis of your provider authority. Because this recommendation is also true for Android
+    package names, you can define your provider authority as an extension of the name
+    of the package containing the provider. For example, if your Android package name is
+    <code>com.example.&lt;appname&gt;</code>, you should give your provider the
+    authority <code>com.example.&lt;appname&gt;.provider</code>.
+</p>
+<h3>Designing a path structure</h3>
+<p>
+    Developers usually create content URIs from the authority by appending paths that point to
+    individual tables. For example, if you have two tables <em>table1</em> and
+    <em>table2</em>, you combine the authority from the previous example to yield the
+    content URIs
+    <code>com.example.&lt;appname&gt;.provider/table1</code> and
+    <code>com.example.&lt;appname&gt;.provider/table2</code>. Paths aren't
+    limited to a single segment, and there doesn't have to be a table for each level of the path.
+</p>
+<h3>Handling content URI IDs</h3>
+<p>
+    By convention, providers offer access to a single row in a table by accepting a content URI
+    with an ID value for the row at the end of the URI. Also by convention, providers match the
+    ID value to the table's <code>_ID</code> column, and perform the requested access against the
+    row that matches.
+</p>
+<p>
+    This convention facilitates a common design pattern for apps accessing a provider. The app
+    does a query against the provider and displays the resulting {@link android.database.Cursor}
+    in a {@link android.widget.ListView} using a {@link android.widget.CursorAdapter}.
+    The definition of {@link android.widget.CursorAdapter} requires one of the columns in the
+    {@link android.database.Cursor} to be <code>_ID</code>
+</p>
+<p>
+    The user then picks one of the displayed rows from the UI in order to look at or modify the
+    data. The app gets the corresponding row from the {@link android.database.Cursor} backing the
+    {@link android.widget.ListView}, gets the <code>_ID</code> value for this row, appends it to
+    the content URI, and sends the access request to the provider. The provider can then do the
+    query or modification against the exact row the user picked.
+</p>
+<h3>Content URI patterns</h3>
+<p>
+    To help you choose which action to take for an incoming content URI, the provider API includes
+    the convenience class {@link android.content.UriMatcher}, which maps content URI "patterns" to
+    integer values. You can use the integer values in a <code>switch</code> statement that
+    chooses the desired action for the content URI or URIs that match a particular pattern.
+</p>
+<p>
+    A content URI pattern matches content URIs using wildcard characters:
+</p>
+    <ul>
+        <li>
+            <strong><code>*</code>:</strong> Matches a string of any valid characters of any length.
+        </li>
+        <li>
+            <strong><code>#</code>:</strong> Matches a string of numeric characters of any length.
+        </li>
+    </ul>
+<p>
+    As an example of designing and coding content URI handling, consider a provider with the
+    authority <code>com.example.app.provider</code> that recognizes the following content URIs
+    pointing to tables:
+</p>
+<ul>
+    <li>
+        <code>content://com.example.app.provider/table1</code>: A table called <code>table1</code>.
+    </li>
+    <li>
+        <code>content://com.example.app.provider/table2/dataset1</code>: A table called
+        <code>dataset1</code>.
+    </li>
+    <li>
+        <code>content://com.example.app.provider/table2/dataset2</code>: A table called
+        <code>dataset2</code>.
+    </li>
+    <li>
+        <code>content://com.example.app.provider/table3</code>: A table called <code>table3</code>.
+    </li>
+</ul>
+<p>
+    The provider also recognizes these content URIs if they have a row ID appended to them, as
+    for example <code>content://com.example.app.provider/table3/1</code> for the row identified by
+    <code>1</code> in <code>table3</code>.
+</p>
+<p>
+    The following content URI patterns would be possible:
+</p>
+<dl>
+    <dt>
+        <code>content://com.example.app.provider/*</code>
+    </dt>
+    <dd>
+        Matches any content URI in the provider.
+    </dd>
+    <dt>
+        <code>content://com.example.app.provider/table2/*</code>:
+    </dt>
+    <dd>
+        Matches a content URI for the tables <code>dataset1</code>
+        and <code>dataset2</code>, but doesn't match content URIs for <code>table1</code> or
+        <code>table3</code>.
+    </dd>
+    <dt>
+        <code>content://com.example.app.provider/table3/#</code>: Matches a content URI
+        for single rows in <code>table3</code>, such as
+        <code>content://com.example.app.provider/table3/6</code> for the row identified by
+        <code>6</code>.
+    </dt>
+</dl>
+<p>
+    The following code snippet shows how the methods in {@link android.content.UriMatcher} work.
+    This code handles URIs for an entire table differently from URIs for a
+    single row, by using the content URI pattern
+    <code>content://&lt;authority&gt;/&lt;path&gt;</code> for tables, and
+    <code>content://&lt;authority&gt;/&lt;path&gt;/&lt;id&gt;</code> for single rows.
+</p>
+<p>
+    The method {@link android.content.UriMatcher#addURI(String, String, int) addURI()} maps an
+    authority and path to an integer value. The method android.content.UriMatcher#match(Uri)
+    match()} returns the integer value for a URI. A <code>switch</code> statement
+    chooses between querying the entire table, and querying for a single record:
+</p>
+<pre class="prettyprint">
+public class ExampleProvider extends ContentProvider {
+...
+    // Creates a UriMatcher object.
+    private static final UriMatcher sUriMatcher;
+...
+    /*
+     * The calls to addURI() go here, for all of the content URI patterns that the provider
+     * should recognize. For this snippet, only the calls for table 3 are shown.
+     */
+...
+    /*
+     * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
+     * in the path
+     */
+    sUriMatcher.addURI("com.example.app.provider", "table3", 1);
+
+    /*
+     * Sets the code for a single row to 2. In this case, the "#" wildcard is
+     * used. "content://com.example.app.provider/table3/3" matches, but
+     * "content://com.example.app.provider/table3 doesn't.
+     */
+    sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
+...
+    // Implements ContentProvider.query()
+    public Cursor query(
+        Uri uri,
+        String[] projection,
+        String selection,
+        String[] selectionArgs,
+        String sortOrder) {
+...
+        /*
+         * Choose the table to query and a sort order based on the code returned for the incoming
+         * URI. Here, too, only the statements for table 3 are shown.
+         */
+        switch (sUriMatcher.match(uri)) {
+
+
+            // If the incoming URI was for all of table3
+            case 1:
+
+                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
+                break;
+
+            // If the incoming URI was for a single row
+            case 2:
+
+                /*
+                 * Because this URI was for a single row, the _ID value part is
+                 * present. Get the last path segment from the URI; this is the _ID value.
+                 * Then, append the value to the WHERE clause for the query
+                 */
+                selection = selection + "_ID = " uri.getLastPathSegment();
+                break;
+
+            default:
+            ...
+                // If the URI is not recognized, you should do some error handling here.
+        }
+        // call the code to actually do the query
+    }
+</pre>
+<p>
+    Another class, {@link android.content.ContentUris}, provides convenience methods for working
+    with the <code>id</code> part of content URIs. The classes {@link android.net.Uri} and
+    {@link android.net.Uri.Builder} include convenience methods for parsing existing
+    {@link android.net.Uri} objects and building new ones.
+</p>
+
+<!-- Implementing the ContentProvider class -->
+<h2 id="ContentProvider">Implementing the ContentProvider Class</h2>
+<p>
+    The {@link android.content.ContentProvider} instance manages access
+    to a structured set of data by handling requests from other applications. All forms
+    of access eventually call {@link android.content.ContentResolver}, which then calls a concrete
+    method of {@link android.content.ContentProvider} to get access.
+</p>
+<h3 id="RequiredAccess">Required methods</h3>
+<p>
+    The abstract class {@link android.content.ContentProvider} defines six abstract methods that
+    you must implement as part of your own concrete subclass. All of these methods except
+    {@link android.content.ContentProvider#onCreate() onCreate()} are called by a client application
+    that is attempting to access your content provider:
+</p>
+<dl>
+    <dt>
+        {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+        query()}
+    </dt>
+    <dd>
+        Retrieve data from your provider. Use the arguments to select the table to
+        query, the rows and columns to return, and the sort order of the result.
+        Return the data as a {@link android.database.Cursor} object.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}
+    </dt>
+    <dd>
+        Insert a new row into your provider. Use the arguments to select the
+        destination table and to get the column values to use. Return a content URI for the
+        newly-inserted row.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
+        update()}
+    </dt>
+    <dd>
+        Update existing rows in your provider. Use the arguments to select the table and rows
+        to update and to get the updated column values. Return the number of rows updated.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
+    </dt>
+    <dd>
+        Delete rows from your provider. Use the arguments to select the table and the rows to
+        delete. Return the number of rows deleted.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#getType(Uri) getType()}
+    </dt>
+    <dd>
+        Return the MIME type corresponding to a content URI. This method is described in more
+        detail in the section <a href="#MIMETypes">Implementing Content Provider MIME Types</a>.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#onCreate() onCreate()}
+    </dt>
+    <dd>
+        Initialize your provider. The Android system calls this method immediately after it
+        creates your provider. Notice that your provider is not created until a
+        {@link android.content.ContentResolver} object tries to access it.
+    </dd>
+</dl>
+<p>
+    Notice that these methods have the same signature as the identically-named
+    {@link android.content.ContentResolver} methods.
+</p>
+<p>
+    Your implementation of these methods should account for the following:
+</p>
+<ul>
+    <li>
+        All of these methods except {@link android.content.ContentProvider#onCreate() onCreate()}
+        can be called by multiple threads at once, so they must be thread-safe. To learn
+        more about multiple threads, see the topic
+        <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">
+        Processes and Threads</a>.
+    </li>
+    <li>
+        Avoid doing lengthy operations in {@link android.content.ContentProvider#onCreate()
+        onCreate()}. Defer initialization tasks until they are actually needed.
+        The section <a href="#OnCreate">Implementing the onCreate() method</a>
+        discusses this in more detail.
+    </li>
+    <li>
+        Although you must implement these methods, your code does not have to do anything except
+        return the expected data type. For example, you may want to prevent other applications
+        from inserting data into some tables. To do this, you can ignore the call to
+        {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} and return
+        0.
+    </li>
+</ul>
+<h3 id="Query">Implementing the query() method</h3>
+<p>
+    The
+    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+    ContentProvider.query()} method must return a {@link android.database.Cursor} object, or if it
+    fails, throw an {@link java.lang.Exception}. If you are using an SQLite database as your data
+    storage, you can simply return the {@link android.database.Cursor} returned by one of the
+    <code>query()</code> methods of the {@link android.database.sqlite.SQLiteDatabase} class.
+    If the query does not match any rows, you should return a {@link android.database.Cursor}
+    instance whose {@link android.database.Cursor#getCount()} method returns 0.
+    You should return <code>null</code> only if an internal error occurred during the query process.
+</p>
+<p>
+    If you aren't using an SQLite database as your data storage, use one of the concrete subclasses
+    of {@link android.database.Cursor}. For example, the {@link android.database.MatrixCursor} class
+    implements a cursor in which each row is an array of {@link java.lang.Object}. With this class,
+    use {@link android.database.MatrixCursor#addRow(Object[]) addRow()} to add a new row.
+</p>
+<p>
+    Remember that the Android system must be able to communicate the {@link java.lang.Exception}
+    across process boundaries. Android can do this for the following exceptions that may be useful
+    in handling query errors:
+</p>
+<ul>
+    <li>
+        {@link java.lang.IllegalArgumentException} (You may choose to throw this if your provider
+        receives an invalid content URI)
+    </li>
+    <li>
+        {@link java.lang.NullPointerException}
+    </li>
+</ul>
+<h3 id="Insert">Implementing the insert() method</h3>
+<p>
+    The {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} method adds a
+    new row to the appropriate table, using the values in the {@link android.content.ContentValues}
+    argument. If a column name is not in the {@link android.content.ContentValues} argument, you
+    may want to provide a default value for it either in your provider code or in your database
+    schema.
+</p>
+<p>
+    This method should return the content URI for the new row. To construct this, append the new
+    row's <code>_ID</code> (or other primary key) value to the table's content URI, using
+    {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}.
+</p>
+<h3 id="Delete">Implementing the delete() method</h3>
+<p>
+    The {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} method
+    does not have to physically delete rows from your data storage. If you are using a sync adapter
+    with your provider, you should consider marking a deleted row
+    with a &quot;delete&quot; flag rather than removing the row entirely. The sync adapter can
+    check for deleted rows and remove them from the server before deleting them from the provider.
+</p>
+<h3 id="Update">Implementing the update() method</h3>
+<p>
+    The {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
+    update()} method takes the same {@link android.content.ContentValues} argument used by
+    {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, and the
+    same <code>selection</code> and <code>selectionArgs</code> arguments used by
+    {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} and
+    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+    ContentProvider.query()}. This may allow you to re-use code between these methods.
+</p>
+<h3 id="OnCreate">Implementing the onCreate() method</h3>
+<p>
+    The Android system calls {@link android.content.ContentProvider#onCreate()
+    onCreate()} when it starts up the provider. You should perform only fast-running initialization
+    tasks in this method, and defer database creation and data loading until the provider actually
+    receives a request for the data. If you do lengthy tasks in
+    {@link android.content.ContentProvider#onCreate() onCreate()}, you will slow down your
+    provider's startup. In turn, this will slow down the response from the provider to other
+    applications.
+</p>
+<p>
+    For example, if you are using an SQLite database you can create
+    a new {@link android.database.sqlite.SQLiteOpenHelper} object in
+    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()},
+    and then create the SQL tables the first time you open the database. To facilitate this, the
+    first time you call {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase
+    getWritableDatabase()}, it automatically calls the
+    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+    SQLiteOpenHelper.onCreate()} method.
+</p>
+<p>
+    The following two snippets demonstrate the interaction between
+    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} and
+    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+    SQLiteOpenHelper.onCreate()}. The first snippet is the implementation of
+    {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}:
+</p>
+<pre class="prettyprint">
+public class ExampleProvider extends ContentProvider
+
+    /*
+     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
+     * in a following snippet.
+     */
+    private MainDatabaseHelper mOpenHelper;
+
+    // Defines the database name
+    private static final String DBNAME = "mydb";
+
+    // Holds the database object
+    private SQLiteDatabase db;
+
+    public boolean onCreate() {
+
+        /*
+         * Creates a new helper object. This method always returns quickly.
+         * Notice that the database itself isn't created or opened
+         * until SQLiteOpenHelper.getWritableDatabase is called
+         */
+        mOpenHelper = new SQLiteOpenHelper(
+            getContext(),        // the application context
+            DBNAME,              // the name of the database)
+            null,                // uses the default SQLite cursor
+            1                    // the version number
+        );
+
+        return true;
+    }
+
+    ...
+
+    // Implements the provider's insert method
+    public Cursor insert(Uri uri, ContentValues values) {
+        // Insert code here to determine which table to open, handle error-checking, and so forth
+
+        ...
+
+        /*
+         * Gets a writeable database. This will trigger its creation if it doesn't already exist.
+         *
+         */
+        db = mOpenHelper.getWritableDatabase();
+    }
+}
+</pre>
+<p>
+    The next snippet is the implementation of
+    {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+    SQLiteOpenHelper.onCreate()}, including a helper class:
+</p>
+<pre class="prettyprint">
+...
+// A string that defines the SQL statement for creating a table
+private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
+    "main " +                       // Table's name
+    "(" +                           // The columns in the table
+    " _ID INTEGER PRIMARY KEY, " +
+    " WORD TEXT"
+    " FREQUENCY INTEGER " +
+    " LOCALE TEXT )";
+...
+/**
+ * Helper class that actually creates and manages the provider's underlying data repository.
+ */
+protected static final class MainDatabaseHelper extends SQLiteOpenHelper {
+
+    /*
+     * Instantiates an open helper for the provider's SQLite data repository
+     * Do not do database creation and upgrade here.
+     */
+    MainDatabaseHelper(Context context) {
+        super(context, DBNAME, null, 1);
+    }
+
+    /*
+     * Creates the data repository. This is called when the provider attempts to open the
+     * repository and SQLite reports that it doesn't exist.
+     */
+    public void onCreate(SQLiteDatabase db) {
+
+        // Creates the main table
+        db.execSQL(SQL_CREATE_MAIN);
+    }
+}
+</pre>
+
+
+<!-- Implementing ContentProvider MIME Types -->
+<h2 id="MIMETypes">Implementing ContentProvider MIME Types</h2>
+<p>
+    The {@link android.content.ContentProvider} class has two methods for returning MIME types:
+</p>
+<dl>
+    <dt>
+        {@link android.content.ContentProvider#getType(Uri) getType()}
+    </dt>
+    <dd>
+        One of the required methods that you must implement for any provider.
+    </dd>
+    <dt>
+        {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
+    </dt>
+    <dd>
+        A method that you're expected to implement if your provider offers files.
+    </dd>
+</dl>
+<h3 id="TableMIMETypes">MIME types for tables</h3>
+<p>
+    The {@link android.content.ContentProvider#getType(Uri) getType()} method returns a
+    {@link java.lang.String} in MIME format that describes the type of data returned by the content
+    URI argument. The {@link android.net.Uri} argument can be a pattern rather than a specific URI;
+    in this case, you should return the type of data associated with content URIs that match the
+    pattern.
+</p>
+<p>
+    For common types of data such as as text, HTML, or JPEG,
+    {@link android.content.ContentProvider#getType(Uri) getType()} should return the standard
+    MIME type for that data. A full list of these standard types is available on the
+    <a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a>
+    website.
+</p>
+<p>
+    For content URIs that point to a row or rows of table data,
+    {@link android.content.ContentProvider#getType(Uri) getType()} should return
+    a MIME type in Android's vendor-specific MIME format:
+</p>
+<ul>
+    <li>
+        Type part: <code>vnd</code>
+    </li>
+    <li>
+        Subtype part:
+        <ul>
+            <li>
+    If the URI pattern is for a single row: <code>android.cursor.<strong>item</strong>/</code>
+            </li>
+            <li>
+    If the URI pattern is for more than one row: <code>android.cursor.<strong>dir</strong>/</code>
+            </li>
+        </ul>
+    </li>
+    <li>
+        Provider-specific part: <code>vnd.&lt;name&gt;</code>.<code>&lt;type&gt;</code>
+        <p>
+            You supply the <code>&lt;name&gt;</code> and <code>&lt;type&gt;</code>.
+            The <code>&lt;name&gt;</code> value should be globally unique,
+            and the <code>&lt;type&gt;</code> value should be unique to the corresponding URI
+            pattern. A good choice for <code>&lt;name&gt;</code> is your company's name or
+            some part of your application's Android package name. A good choice for the
+            <code>&lt;type&gt;</code> is a string that identifies the table associated with the
+            URI.
+        </p>
+
+    </li>
+</ul>
+<p>
+    For example, if a provider's authority is
+    <code>com.example.app.provider</code>, and it exposes a table named
+    <code>table1</code>, the MIME type for multiple rows in <code>table1</code> is:
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1
+</pre>
+<p>
+    For a single row of <code>table1</code>, the MIME type is:
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1
+</pre>
+<h3 id="FileMIMETypes">MIME types for files</h3>
+<p>
+    If your provider offers files, implement
+    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}.
+    The method returns a {@link java.lang.String} array of MIME types for the files your provider
+    can return for a given content URI. You should filter the MIME types you offer by the MIME type
+    filter argument, so that you return only those MIME types that the client wants to handle.
+</p>
+<p>
+    For example, consider a provider that offers photo images as files in <code>.jpg</code>,
+    <code>.png</code>, and <code>.gif</code> format.
+    If an application calls {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+    ContentResolver.getStreamTypes()} with the filter string <code>image/*</code> (something that
+    is an &quot;image&quot;),
+    then the {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+    ContentProvider.getStreamTypes()} method should return the array:
+</p>
+<pre>
+{ &quot;image/jpeg&quot;, &quot;image/png&quot;, &quot;image/gif&quot;}
+</pre>
+<p>
+    If the app is only interested in <code>.jpg</code> files, then it can call
+    {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+    ContentResolver.getStreamTypes()} with the filter string <code>*\/jpeg</code>, and
+    {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+    ContentProvider.getStreamTypes()} should return:
+<pre>
+{&quot;image/jpeg&quot;}
+</pre>
+<p>
+    If your provider doesn't offer any of the MIME types requested in the filter string,
+    {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
+    should return <code>null</code>.
+</p>
+
+
+<!--  Implementing a Contract Class -->
+<h2 id="ContractClass">Implementing a Contract Class</h2>
+<p>
+    A contract class is a <code>public final</code> class that contains constant definitions for the
+    URIs, column names, MIME types, and other meta-data that pertain to the provider. The class
+    establishes a contract between the provider and other applications by ensuring that the provider
+    can be correctly accessed even if there are changes to the actual values of URIs, column names,
+    and so forth.
+</p>
+<p>
+    A contract class also helps developers because it usually has mnemonic names for its constants,
+    so developers are less likely to use incorrect values for column names or URIs. Since it's a
+    class, it can contain Javadoc documentation. Integrated development environments such as
+    Eclipse can auto-complete constant names from the contract class and display Javadoc for the
+    constants.
+</p>
+<p>
+    Developers can't access the contract class's class file from your application, but they can
+    statically compile it into their application from a <code>.jar</code> file you provide.
+</p>
+<p>
+    The {@link android.provider.ContactsContract} class and its nested classes are examples of
+    contract classes.
+</p>
+<h2 id="Permissions">Implementing Content Provider Permissions</h2>
+<p>
+    Permissions and access for all aspects of the Android system are described in detail in the
+    topic <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>.
+    The topic <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a> also
+    described the security and permissions in effect for various types of storage.
+    In brief, the important points are:
+</p>
+<ul>
+    <li>
+        By default, data files stored on the device's internal storage are private to your
+        application and provider.
+    </li>
+    <li>
+        {@link android.database.sqlite.SQLiteDatabase} databases you create are private to your
+        application and provider.
+    </li>
+    <li>
+        By default, data files that you save to external storage are <em>public</em> and
+        <em>world-readable</em>. You can't use a content provider to restrict access to files in
+        external storage, because other applications can use other API calls to read and write them.
+    </li>
+    <li>
+        The method calls for opening or creating files or SQLite databases on your device's internal
+        storage can potentially give both read and write access to all other applications. If you
+        use an internal file or database as your provider's repository, and you give it
+        "world-readable" or "world-writeable" access, the permissions you set for your provider in
+        its manifest won't protect your data. The default access for files and databases in
+        internal storage is "private", and for your provider's repository you shouldn't change this.
+    </li>
+</ul>
+<p>
+    If you want to use content provider permissions to control access to your data, then you should
+    store your data in internal files, SQLite databases, or the &quot;cloud&quot; (for example,
+    on a remote server), and you should keep files and databases private to your application.
+</p>
+<h3>Implementing permissions</h3>
+<p>
+    All applications can read from or write to your provider, even if the underlying data is
+    private, because by default your provider does not have permissions set. To change this,
+    set permissions for your provider in your manifest file, using attributes or child
+    elements of the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+    &lt;provider&gt;</a></code> element. You can set permissions that apply to the entire provider,
+    or to certain tables, or even to certain records, or all three.
+</p>
+<p>
+    You define permissions for your provider with one or more
+    <code><a href="{@docRoot}guide/topics/manifest/permission-element.html">
+    &lt;permission&gt;</a></code> elements in your manifest file. To make the
+    permission unique to your provider, use Java-style scoping for the
+    <code><a href="{@docRoot}guide/topics/manifest/permission-element.html#nm">
+    android:name</a></code> attribute. For example, name the read permission
+    <code>com.example.app.provider.permission.READ_PROVIDER</code>.
+
+</p>
+<p>
+    The following list describes the scope of provider permissions, starting with the
+    permissions that apply to the entire provider and then becoming more fine-grained.
+    More fine-grained permissions take precedence over ones with larger scope:
+</p>
+<dl>
+    <dt>
+        Single read-write provider-level permission
+    </dt>
+    <dd>
+        One permission that controls both read and write access to the entire provider, specified
+        with the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
+        android:permission</a></code> attribute of the
+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+        &lt;provider&gt;</a></code> element.
+    </dd>
+    <dt>
+        Separate read and write provider-level permission
+    </dt>
+    <dd>
+        A read permission and a write permission for the entire provider. You specify them
+        with the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
+        android:readPermission</a></code> and
+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
+        android:writePermission</a></code> attributes of the
+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+        &lt;provider&gt;</a></code> element. They take precedence over the permission required by
+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
+        android:permission</a></code>.
+    </dd>
+    <dt>
+        Path-level permission
+    </dt>
+    <dd>
+        Read, write, or read/write permission for a content URI in your provider. You specify
+        each URI you want to control with a
+        <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html">
+        &lt;path-permission&gt;</a></code> child element of the
+        <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+        &lt;provider&gt;</a></code> element. For each content URI you specify, you can specify a
+        read/write permission, a read permission, or a write permission, or all three. The read and
+        write permissions take precedence over the read/write permission. Also, path-level
+        permission takes precedence over provider-level permissions.
+    </dd>
+    <dt>
+        Temporary permission
+    </dt>
+    <dd>
+        A permission level that grants temporary access to an application, even if the application
+        doesn't have the permissions that are normally required. The temporary
+        access feature reduces the number of permissions an application has to request in
+        its manifest. When you turn on temporary permissions, the only applications that need
+        &quot;permanent&quot; permissions for your provider are ones that continually access all
+        your data.
+        <p>
+            Consider the permissions you need to implement an email provider and app, when you
+            want to allow an outside image viewer application to display photo attachments from your
+            provider. To give the image viewer the necessary access without requiring permissions,
+            set up temporary permissions for content URIs for photos. Design your email app so
+            that when the user wants to display a photo, the app sends an intent containing the
+            photo's content URI and permission flags to the image viewer. The image viewer can
+            then query your email provider to retrieve the photo, even though the viewer doesn't
+            have the normal read permission for your provider.
+        </p>
+        <p>
+            To turn on temporary permissions, either set the
+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+            android:grantUriPermissions</a></code> attribute of the
+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code> element, or add one or more
+            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
+            &lt;grant-uri-permission&gt;</a></code> child elements to your
+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code> element. If you use temporary permissions, you have to call
+            {@link android.content.Context#revokeUriPermission(Uri, int)
+            Context.revokeUriPermission()} whenever you remove support for a content URI from your
+            provider, and the content URI is associated with a temporary permission.
+        </p>
+        <p>
+            The attribute's value determines how much of your provider is made accessible.
+            If the attribute is set to <code>true</code>, then the system will grant temporary
+            permission to your entire provider, overriding any other permissions that are required
+            by your provider-level or path-level permissions.
+        </p>
+        <p>
+            If this flag is set to <code>false</code>, then you must add
+            <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
+            &lt;grant-uri-permission&gt;</a></code> child elements to your
+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code> element. Each child element specifies the content URI or
+            URIs for which temporary access is granted.
+        </p>
+        <p>
+            To delegate temporary access to an application, an intent must contain
+            the {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} or the
+            {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} flags, or both. These
+            are set with the {@link android.content.Intent#setFlags(int) setFlags()} method.
+        </p>
+        <p>
+            If the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+            android:grantUriPermissions</a></code> attribute is not present, it's assumed to be
+            <code>false</code>.
+        </p>
+    </dd>
+</dl>
+
+
+
+<!-- The Provider Element -->
+<h2 id="ProviderElement">The &lt;provider&gt; Element</h2>
+<p>
+    Like {@link android.app.Activity} and {@link android.app.Service} components,
+    a subclass of {@link android.content.ContentProvider}
+    must be defined in the manifest file for its application, using the
+    <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+    &lt;provider&gt;</a></code> element. The Android system gets the following information from
+    the element:
+<dl>
+    <dt>
+        Authority
+        (<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code
+        android:authorities}</a>)
+    </dt>
+    <dd>
+        Symbolic names that identify the entire provider within the system. This
+        attribute is described in more detail in the section
+        <a href="#ContentURI">Designing Content URIs</a>.
+    </dd>
+    <dt>
+        Provider class name
+        (<code>
+<a href="{@docRoot}guide/topics/manifest/provider-element.html#nm">android:name</a>
+        </code>)
+    </dt>
+    <dd>
+        The class that implements {@link android.content.ContentProvider}. This class is
+        described in more detail in the section
+        <a href="#ContentProvider">Implementing the ContentProvider Class</a>.
+    </dd>
+    <dt>
+        Permissions
+    </dt>
+    <dd>
+        Attributes that specify the permissions that other applications must have in order to access
+        the provider's data:
+        <ul>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+                android:grantUriPermssions</a></code>: Temporary permission flag.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
+                android:permission</a></code>: Single provider-wide read/write permission.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
+                android:readPermission</a></code>: Provider-wide read permission.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
+                android:writePermission</a></code>: Provider-wide write permission.
+            </li>
+        </ul>
+        <p>
+            Permissions and their corresponding attributes are described in more
+            detail in the section
+            <a href="#Permissions">Implementing Content Provider Permissions</a>.
+        </p>
+    </dd>
+    <dt>
+        Startup and control attributes
+    </dt>
+    <dd>
+        These attributes determine how and when the Android system starts the provider, the
+        process characteristics of the provider, and other run-time settings:
+        <ul>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#enabled">
+                android:enabled</a></code>: Flag allowing the system to start the provider.
+            </li>
+              <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
+                android:exported</a></code>: Flag allowing other applications to use this provider.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#init">
+                android:initOrder</a></code>: The order in which this provider should be started,
+                relative to other providers in the same process.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#multi">
+                android:multiProcess</a></code>: Flag allowing the system to start the provider
+                in the same process as the calling client.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#proc">
+                android:process</a></code>: The name of the process in which the provider should
+                run.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#sync">
+                android:syncable</a></code>: Flag indicating that the provider's data is to be
+                sync'ed with data on a server.
+            </li>
+        </ul>
+        <p>
+            The attributes are fully documented in the dev guide topic for the
+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code>
+            element.
+        </p>
+    </dd>
+    <dt>
+        Informational attributes
+    </dt>
+    <dd>
+        An optional icon and label for the provider:
+        <ul>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#icon">
+                android:icon</a></code>: A drawable resource containing an icon for the provider.
+                The icon appears next to the provider's label in the list of apps in
+                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
+            </li>
+            <li>
+                <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label">
+                android:label</a></code>: An informational label describing the provider or its
+                data, or both. The label appears in the list of apps in
+                <em>Settings</em> &gt; <em>Apps</em> &gt; <em>All</em>.
+            </li>
+        </ul>
+        <p>
+            The attributes are fully documented in the dev guide topic for the
+            <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+            &lt;provider&gt;</a></code> element.
+        </p>
+    </dd>
+</dl>
+
+<!-- Intent Access -->
+<h2 id="Intents">Intents and Data Access</h2>
+<p>
+    Applications can access a content provider indirectly with an {@link android.content.Intent}.
+    The application does not call any of the methods of {@link android.content.ContentResolver} or
+    {@link android.content.ContentProvider}. Instead, it sends an intent that starts an activity,
+    which is often part of the provider's own application. The destination activity is in charge of
+    retrieving and displaying the data in its UI. Depending on the action in the intent, the
+    destination activity may also prompt the user to make modifications to the provider's data.
+    An intent may also contain &quot;extras&quot; data that the destination activity displays
+    in the UI; the user then has the option of changing this data before using it to modify the
+    data in the provider.
+</p>
+<p>
+
+</p>
+<p>
+    You may want to use intent access to help ensure data integrity. Your provider may depend
+    on having data inserted, updated, and deleted according to strictly defined business logic. If
+    this is the case, allowing other applications to directly modify your data may lead to
+    invalid data. If you want developers to use intent access, be sure to document it thoroughly.
+    Explain to them why intent access using your own application's UI is better than trying to
+    modify the data with their code.
+</p>
+<p>
+    Handling an incoming intent that wishes to modify your provider's data is no different from
+    handling other intents. You can learn more about using intents by reading the topic
+    <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>.
+</p>
diff --git a/docs/html/guide/topics/providers/content-providers.jd b/docs/html/guide/topics/providers/content-providers.jd
index 95331ce..1707f03 100644
--- a/docs/html/guide/topics/providers/content-providers.jd
+++ b/docs/html/guide/topics/providers/content-providers.jd
@@ -1,922 +1,96 @@
 page.title=Content Providers
 @jd:body
-
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>In this document</h2>
+
+<!-- In this document -->
+<h2>Topics</h2>
 <ol>
-<li><a href="#basics">Content provider basics</a></li>
-<li><a href="#querying">Querying a content provider</a></li>
-<li><a href="#modifying">Modifying data in a provider</a></li>
-<li><a href="#creating">Creating a content provider</a></li>
-<li><a href="#urisum">Content URI summary</a></li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Content Provider Basics</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+        Creating a Content Provider</a>
+    </li>
+    <li>
+        <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a>
+    </li>
 </ol>
 
-<h2>Key classes</h2>
-<ol>
-<li>{@link android.content.ContentProvider}</li>
-<li>{@link android.content.ContentResolver}</li>
-<li>{@link android.database.Cursor}</li>
-</ol>
-
-<h2>See also</h2>
-<ol>
-  <li><a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a></li>
-</ol>
+    <!-- Related Samples -->
+<h2>Related Samples</h2>
+    <ol>
+        <li>
+            <a href="{@docRoot}resources/samples/ContactManager/index.html">
+            Contact Manager</a> application
+        </li>
+        <li>
+        <a
+        href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
+        &quot;Cursor (People)&quot;
+        </a>
+        </li>
+        <li>
+        <a
+        href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
+        &quot;Cursor (Phones)&quot;</a>
+        </li>
+    </ol>
 </div>
 </div>
-
 <p>
-Content providers store and retrieve data and make it accessible to all 
-applications.  They're the only way to share data across applications; there's 
-no common storage area that all Android packages can access.
-</p>   
-
-<p>
-Android ships with a number of content providers for common data types 
-(audio, video, images, personal contact information, and so on).  You can 
-see some of them listed in the {@link android.provider android.provider} 
-package.  You can query these providers for the data they contain (although,
-for some, you must acquire the proper permission to read the data).
-</p>   
-
-<p class="note"><strong>Note:</strong> Android 4.0 introduces the Calendar
-Provider. For more information, see <a
-href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar
-Provider</a>.</p>
-<p>
-If you want to make your own data public, you have two options:  You can 
-create your own content provider (a {@link android.content.ContentProvider} 
-subclass) or you can add the data to an existing provider &mdash; if there's 
-one that controls the same type of data and you have permission to write to it. 
-</p>   
-
-<p>
-This document is an introduction to using content providers.  After a 
-brief discussion of the fundamentals, it explores how to query a content 
-provider, how to modify data controlled by a provider, and how to create
-a content provider of your own.
-</p>   
-
-
-<h2><a name="basics"></a>Content Provider Basics</h2>
-
-<p>
-How a content provider actually stores its data under the covers is 
-up to its designer.  But all content providers implement a common interface 
-for querying the provider and returning results &mdash; as well as for 
-adding, altering, and deleting data.
-</p>   
-
-<p>
-It's an interface that clients use indirectly, most generally through 
-{@link android.content.ContentResolver} objects.  You get a ContentResolver 
-by calling <code>{@link android.content.Context#getContentResolver 
-getContentResolver()}</code> from within the implementation of an Activity 
-or other application component:
-</p>   
-
-<pre>ContentResolver cr = getContentResolver();</pre>
-
-<p>
-You can then use the ContentResolver's methods to interact with whatever 
-content providers you're interested in.
-</p>   
-
-<p>
-When a query is initiated, the Android system identifies the content provider 
-that's the target of the query and makes sure that it is up and running.  
-The system instantiates all ContentProvider objects; you never need to do it 
-on your own.  In fact, you never deal directly with ContentProvider objects 
-at all.  Typically, there's just a single instance of each type of 
-ContentProvider.  But it can communicate with multiple ContentResolver objects 
-in different applications and processes.  The interaction between processes is 
-handled by the ContentResolver and ContentProvider classes.
-</p>   
-
-
-<h3>The data model</h3>
-
-<p>
-Content providers expose their data as a simple table on a database model, 
-where each row is a record and each column is data of a particular type 
-and meaning.  For example, information about people and their phone numbers 
-might be exposed as follows: 
-</p>   
-
-<table>
-   <tr>
-      <th scope="col">_ID</th>
-      <th scope="col">NUMBER</th>
-      <th scope="col">NUMBER_KEY</th>
-      <th scope="col">LABEL</th>
-      <th scope="col">NAME</th>
-      <th scope="col">TYPE</th>
-   </tr>
-   <tr>
-      <td>13</td>
-      <td>(425) 555 6677</td>
-      <td>425 555 6677</td>
-      <td>Kirkland office</td>
-      <td>Bully Pulpit</td>
-      <td>{@code TYPE_WORK}</td>
-   </tr>
-   <tr>
-      <td>44</td>
-      <td>(212) 555-1234</td>
-      <td>212 555 1234</td>
-      <td>NY apartment</td>
-      <td>Alan Vain</td>
-      <td>{@code TYPE_HOME}</td>
-   </tr>
-   <tr>
-      <td>45</td>
-      <td>(212) 555-6657</td>
-      <td>212 555 6657</td>
-      <td>Downtown office</td>
-      <td>Alan Vain</td>
-      <td>{@code TYPE_MOBILE}</td>
-   </tr>
-   <tr>
-      <td>53</td>
-      <td>201.555.4433</td>
-      <td>201 555 4433</td>
-      <td>Love Nest</td>
-      <td>Rex Cars</td>
-      <td>{@code TYPE_HOME}</td>
-   </tr>
-</table>
-
-<p>
-Every record includes a numeric {@code _ID} field that uniquely identifies 
-the record within the table.  IDs can be used to match records in related 
-tables &mdash; for example, to find a person's phone number in one table 
-and pictures of that person in another.
-</p>   
-
-<p>
-A query returns a {@link android.database.Cursor} object that can move from 
-record to record and column to column to read the contents of each field.  
-It has specialized methods for reading each type of data.  So, to read a field, 
-you must know what type of data the field contains.  (There's more on query 
-results and Cursor objects later.)
-</p>   
-
-
-<h3><a name="uri"></a>URIs</h3>
-
-<p>
-Each content provider exposes a public URI (wrapped as a {@link android.net.Uri} 
-object) that uniquely identifies its data set.  A content provider that controls 
-multiple data sets (multiple tables) exposes a separate URI for each one.  All 
-URIs for providers begin with the string "{@code content://}".  The {@code content:} 
-scheme identifies the data as being controlled by a content provider.
-</p>   
-
-<p>
-If you're defining a content provider, it's a good idea to also define a 
-constant for its URI, to simplify client code and make future updates cleaner.  
-Android defines {@code CONTENT_URI} constants for all the providers that come 
-with the platform.  For example, the URI for the table that matches 
-phone numbers to people and the URI for the table that holds pictures of 
-people (both controlled by the Contacts content provider) are:
-</p>   
-
-<p>
-<p style="margin-left: 2em">{@code android.provider.Contacts.Phones.CONTENT_URI}
-<br/>{@code android.provider.Contacts.Photos.CONTENT_URI}
+    Content providers manage access to a structured set of data. They encapsulate the
+    data, and provide mechanisms for defining data security. Content providers are the standard
+    interface that connects data in one process with code running in another process.
 </p>
-
 <p>
-The URI constant is used in all interactions with the content provider. 
-Every {@link android.content.ContentResolver} method takes the URI 
-as its first argument.  It's what identifies which provider the ContentResolver 
-should talk to and which table of the provider is being targeted.
-</p>   
-
-
-<h2><a name="querying"></a>Querying a Content Provider</h2>
-
-<p>
-You need three pieces of information to query a content provider:
-</p>   
-
-<ul>
-<li>The URI that identifies the provider</li>
-<li>The names of the data fields you want to receive</li>
-<li>The data types for those fields</li>
-</ul>
-
-<p>
-If you're querying a particular record, you also need the ID for that record.
-</p>   
-
-
-<h3>Making the query</h3>
-
-<p>
-To query a content provider, you can use either the 
-<code>{@link android.content.ContentResolver#query ContentResolver.query()}</code> 
-method or the <code>{@link  android.app.Activity#managedQuery 
-Activity.managedQuery()}</code> method. 
-Both methods take the same set of arguments, and both return a 
-Cursor object.  However, {@code managedQuery()} 
-causes the activity to manage the life cycle of the Cursor.  A managed Cursor 
-handles all of the niceties, such as unloading itself when the activity pauses, 
-and requerying itself when the activity restarts.  You can ask an Activity to 
-begin managing an unmanaged Cursor object for you by calling 
-<code>{@link android.app.Activity#startManagingCursor 
-Activity.startManagingCursor()}</code>. 
-</p>   
-
-<p>
-The first argument to either <code>{@link android.content.ContentResolver#query query()}</code> 
-or <code>{@link android.app.Activity#managedQuery managedQuery()}</code> is the provider URI 
-&mdash; the {@code CONTENT_URI} constant that identifies a particular 
-ContentProvider and data set (see <a href="#uri">URIs</a> earlier).
-</p>   
-
-<p>
-To restrict a query to just one record, you can append the {@code _ID} value for 
-that record to the URI &mdash; that is, place a string matching the ID as the 
-last segment of the path part of the URI.  For example, if the ID is 23, 
-the URI would be:
-</p>   
-
-<p style="margin-left: 2em">{@code content://. . . ./23}</p>   
-
-<p>
-There are some helper methods, particularly 
-<code>{@link android.content.ContentUris#withAppendedId 
-ContentUris.withAppendedId()}</code> and <code>{@link 
-android.net.Uri#withAppendedPath Uri.withAppendedPath()}</code>, 
-that make it easy to append an ID to a URI.  Both are static methods that return 
-a Uri object with the ID added.  So, for example, if you were looking for record 
-23 in the database of people contacts, you might construct a query as follows:
-</p>   
-
-<pre>
-import android.provider.Contacts.People;
-import android.content.ContentUris;
-import android.net.Uri;
-import android.database.Cursor;
-
-// Use the ContentUris method to produce the base URI for the contact with _ID == 23.
-Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);
-
-// Alternatively, use the Uri method to produce the base URI.
-// It takes a string rather than an integer.
-Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");
-
-// Then query for this specific record:
-Cursor cur = managedQuery(myPerson, null, null, null, null);
-</pre>
-
-<p>
-The other arguments to the <code>{@link android.content.ContentResolver#query query()}</code> 
-and <code>{@link android.app.Activity#managedQuery managedQuery()}</code> methods delimit 
-the query in more detail.  They are:
-</p>   
-
-<ul>
-<li>The names of the data columns that should be returned.  A {@code null} 
-value returns all columns.  Otherwise, only columns that are listed by name
-are returned.  All the content providers that come with the platform define 
-constants for their columns.  For example, the 
-{@link android.provider.Contacts.Phones android.provider.Contacts.Phones} class 
-defines constants for the names of the columns in the phone table illustrated 
-earlier &mdash; {@code _ID}, {@code NUMBER}, {@code NUMBER_KEY}, {@code NAME},
-and so on.</li>
-
-<li><p>A filter detailing which rows to return, formatted as an SQL {@code WHERE} 
-clause (excluding the {@code WHERE} itself).  A {@code null} value returns 
-all rows (unless the URI limits the query to a single record).</p></li>
-
-<li><p>Selection arguments.</p></li>
-
-<li><p>A sorting order for the rows that are returned, formatted as an SQL 
-{@code ORDER BY} clause (excluding the {@code ORDER BY} itself).  A {@code null} 
-value returns the records in the default order for the table, which may be
-unordered.</p></li>  
-</ul>
-
-<p>
-Let's look at an example query to retrieve a list of contact names and their 
-primary phone numbers:
+    When you want to access data in a content provider, you use the
+    {@link android.content.ContentResolver} object in your
+    application's {@link android.content.Context} to communicate with the provider as a client.
+    The {@link android.content.ContentResolver} object communicates with the provider object, an
+    instance of a class that implements {@link android.content.ContentProvider}. The provider
+    object receives data requests from clients, performs the requested action, and
+    returns the results.
 </p>
-
-<pre>
-import android.provider.Contacts.People;
-import android.database.Cursor;
-
-// Form an array specifying which columns to return. 
-String[] projection = new String[] {
-                             People._ID,
-                             People._COUNT,
-                             People.NAME,
-                             People.NUMBER
-                          };
-
-// Get the base URI for the People table in the Contacts content provider.
-Uri contacts =  People.CONTENT_URI;
-
-// Make the query. 
-Cursor managedCursor = managedQuery(contacts,
-                         projection, // Which columns to return 
-                         null,       // Which rows to return (all rows)
-                         null,       // Selection arguments (none)
-                         // Put the results in ascending order by name
-                         People.NAME + " ASC");
-</pre>
-
 <p>
-This query retrieves data from the People table of the Contacts content 
-provider.  It gets the name, primary phone number, and unique record ID for
-each contact.  It also reports the number of records that are returned as 
-the {@code _COUNT} field of each record.
+    You don't need to develop your own provider if you don't intend to share your data with
+    other applications. However, you do need your own provider to provide custom search
+    suggestions in your own application. You also need your own provider if you want to copy and
+    paste complex data or files from your application to other applications.
 </p>
-
 <p>
-The constants for the names of the columns are defined in various interfaces 
-&mdash; {@code _ID} and {@code _COUNT} in 
-{@link android.provider.BaseColumns BaseColumns}, {@code NAME} in {@link android.provider.Contacts.PeopleColumns PeopleColumns}, and {@code NUMBER} 
-in {@link android.provider.Contacts.PhonesColumns PhoneColumns}.  The 
-{@link android.provider.Contacts.People Contacts.People} class implements 
-each of these interfaces, which is why the code example above could refer 
-to them using just the class name. 
+    Android itself includes content providers that manage data such as audio, video, images, and
+    personal contact information. You can see some of them listed in the reference
+    documentation for the
+    <code><a href="{@docRoot}reference/android/provider/package-summary.html">android.provider</a>
+    </code> package. With some restrictions, these providers are accessible to any Android
+    application.
+</p><p>
+    The following topics describe content providers in more detail:
 </p>
-
-
-<h3>What a query returns</h3>
-
-<p>
-A query returns a set of zero or more database records.  The names of the 
-columns, their default order, and their data types are specific to each 
-content provider. 
-But every provider has an {@code _ID} column, which holds a unique numeric 
-ID for each record.  Every provider can also report the number
-of records returned as the {@code _COUNT} column; its value 
-is the same for all rows. 
-</p>
-
-<p> 
-Here is an example result set for the query in the previous section:
-</p>
-
-<table border="1">
-   <tbody>
-      <tr>
-         <th scope="col">_ID</th>
-         <th scope="col">_COUNT</th>
-         <th scope="col">NAME</th>
-         <th scope="col">NUMBER</th>     
-      </tr>
-      <tr>
-         <td>44</td>
-         <td>3</td>
-         <td>Alan Vain</td>
-         <td>212 555 1234</td>   
-      </tr>
-      <tr>
-         <td>13</td>
-         <td>3</td>
-         <td>Bully Pulpit</td>
-         <td>425 555 6677</td>   
-      </tr>
-      <tr>
-         <td>53</td>
-         <td>3</td>
-         <td>Rex Cars</td>
-         <td>201 555 4433</td>
-      </tr>
-   </tbody>
-</table>
-
-<p>
-The retrieved data is exposed by a {@link android.database.Cursor Cursor} 
-object that can be used to iterate backward or forward through the result 
-set.  You can use this object only to read the data.  To add, modify, or 
-delete data, you must use a ContentResolver object.
-</p>
-
-
-<h3>Reading retrieved data</h3>
-
-<p>
-The Cursor object returned by a query provides access to a recordset of
-results.  If you have queried for a specific record by ID, this set will
-contain only one value.  Otherwise, it can contain multiple values.  
-(If there are no matches, it can also be empty.)  You 
-can read data from specific fields in the record, but you must know the 
-data type of the field, because the Cursor object has a separate method
-for reading each type of data &mdash; such as <code>{@link 
-android.database.Cursor#getString getString()}</code>, <code>{@link 
-android.database.Cursor#getInt getInt()}</code>, and <code>{@link 
-android.database.Cursor#getFloat getFloat()}</code>.  
-(However, for most types, if you call the method for reading strings, 
-the Cursor object will give you the String representation of the data.)  
-The Cursor lets you request the column name from the index of the column, 
-or the index number from the column name.
-</p>
-
-<p>
-The following snippet demonstrates reading names and phone numbers from
-the query illustrated earlier:
-</p>
-
-<pre>
-import android.provider.Contacts.People;
-
-private void getColumnData(Cursor cur){ 
-    if (cur.moveToFirst()) {
-
-        String name; 
-        String phoneNumber; 
-        int nameColumn = cur.getColumnIndex(People.NAME); 
-        int phoneColumn = cur.getColumnIndex(People.NUMBER);
-        String imagePath; 
-    
-        do {
-            // Get the field values
-            name = cur.getString(nameColumn);
-            phoneNumber = cur.getString(phoneColumn);
-           
-	    // Do something with the values. 
-            ... 
-
-        } while (cur.moveToNext());
-
-    }
-}
-</pre>
-
-<p>
-If a query can return binary data, such as an image or sound, the data 
-may be directly entered in the table or the table entry for that data may be
-a string specifying a {@code content:} URI that you can use to get the data.  
-In general, smaller amounts of data (say, from 20 to 50K or less) are most often 
-directly entered in the table and can be read by calling 
-<code>{@link android.database.Cursor#getBlob Cursor.getBlob()}</code>.  
-It returns a byte array.
-</p>
-  
-<p>
-If the table entry is a {@code content:} URI, you should never try to open 
-and read the file directly (for one thing, permissions problems can make this 
-fail).  Instead, you should call 
-<code>{@link android.content.ContentResolver#openInputStream 
-ContentResolver.openInputStream()}</code> to get an 
-{@link java.io.InputStream} object that you can use to read the data.  
-</p>
-
-
-<h2><a name="modifying"></a>Modifying Data</h2>
-
-<p>
-Data kept by a content provider can be modified by:
-</p>
-
-<ul>
-<p><li>Adding new records</li>
-<li>Adding new values to existing records</li>
-<li>Batch updating existing records</li>
-<li>Deleting records</li>
-</ul>
-
-<p>
-All data modification is accomplished using {@link android.content.ContentResolver}
-methods.  Some content providers require a more restrictive permission for writing
-data than they do for reading it.  If you don't have permission to write to a 
-content provider, the ContentResolver methods will fail.
-</p>
-
-
-<h3>Adding records</h3>
-
-<p>
-To add a new record to a content provider, first set up a map of key-value pairs 
-in a {@link android.content.ContentValues} object, where each key matches 
-the name of a column in the content provider and the value is the desired 
-value for the new record in that column.  Then call <code>{@link 
-android.content.ContentResolver#insert ContentResolver.insert()}</code> and pass 
-it the URI of the provider and the ContentValues map.  This method returns 
-the full URI of the new record &mdash; that is, the provider's URI with 
-the appended ID for the new record.  You can then use this URI to query and 
-get a Cursor over the new record, and to further modify the record.  
-Here's an example:
-</p>
-
-<pre>
-import android.provider.Contacts.People;
-import android.content.ContentResolver;
-import android.content.ContentValues; 
-
-ContentValues values = new ContentValues();
-
-// Add Abraham Lincoln to contacts and make him a favorite.
-values.put(People.NAME, "Abraham Lincoln");
-// 1 = the new contact is added to favorites
-// 0 = the new contact is not added to favorites
-values.put(People.STARRED, 1);
-
-Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
-</pre>
-
-
-<h3>Adding new values</h3>
-
-<p>
-Once a record exists, you can add new information to it or modify 
-existing information.  For example, the next step in the example above would 
-be to add contact information &mdash; like a phone number or an IM or e-mail 
-address &mdash; to the new entry.  
-</p>
-
-<p>
-The best way to add to a record in the Contacts database is to append 
-the name of the table where the new data goes to the URI for the 
-record, then use the amended URI to add the new data values.  Each
-Contacts table exposes a name for this purpose as a {@code 
-CONTENT_DIRECTORY} constant.  The following code continues the previous 
-example by adding a phone number and e-mail address for the record
-just created:
-</p>
-
-<pre>
-Uri phoneUri = null;
-Uri emailUri = null;
-
-// Add a phone number for Abraham Lincoln.  Begin with the URI for
-// the new record just returned by insert(); it ends with the _ID
-// of the new record, so we don't have to add the ID ourselves.
-// Then append the designation for the phone table to this URI,
-// and use the resulting URI to insert the phone number.
-phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
-
-values.clear();
-values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
-values.put(People.Phones.NUMBER, "1233214567");
-getContentResolver().insert(phoneUri, values);
-
-// Now add an email address in the same way.
-emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY);
-
-values.clear();
-// ContactMethods.KIND is used to distinguish different kinds of
-// contact methods, such as email, IM, etc. 
-values.put(People.ContactMethods.KIND, Contacts.KIND_EMAIL);
-values.put(People.ContactMethods.DATA, "test@example.com");
-values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME);
-getContentResolver().insert(emailUri, values);   
-</pre>
-
-<p>
-You can place small amounts of binary data into a table by calling 
-the version of <code>{@link android.content.ContentValues#put 
-ContentValues.put()}</code> that takes a byte array.  
-That would work for a small icon-like image or a short audio clip, for example.  
-However, if you have a large amount of binary data to add, such as a photograph
-or a complete song, put a {@code content:} URI for the data in the table and call
-<code>{@link android.content.ContentResolver#openOutputStream 
-ContentResolver.openOutputStream()}</code> 
-with the file's URI.  (That causes the content provider to store the data 
-in a file and record the file path in a hidden field of the record.)
-</p>
-
-<p>
-In this regard, the {@link android.provider.MediaStore} content 
-provider, the main provider that dispenses image, audio, and video 
-data, employs a special convention:  The same URI that is used with 
-{@code query()} or {@code managedQuery()} to get meta-information 
-about the binary data (such as, the caption of a photograph or the
-date it was taken) is used with {@code openInputStream()} 
-to get the data itself.  Similarly, the same URI that is used with
-{@code insert()} to put meta-information into a MediaStore record 
-is used with {@code openOutputStream()} to place the binary data there.
-The following code snippet illustrates this convention:
-</p>
-
-<pre>
-import android.provider.MediaStore.Images.Media;
-import android.content.ContentValues;
-import java.io.OutputStream;
-
-// Save the name and description of an image in a ContentValues map.  
-ContentValues values = new ContentValues(3);
-values.put(Media.DISPLAY_NAME, "road_trip_1");
-values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles");
-values.put(Media.MIME_TYPE, "image/jpeg");
-
-// Add a new record without the bitmap, but with the values just set.
-// insert() returns the URI of the new record.
-Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
-
-// Now get a handle to the file for that record, and save the data into it.
-// Here, sourceBitmap is a Bitmap object representing the file to save to the database.
-try {
-    OutputStream outStream = getContentResolver().openOutputStream(uri);
-    sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
-    outStream.close();
-} catch (Exception e) {
-    Log.e(TAG, "exception while writing image", e);
-}
-</pre>
-
-
-<h3>Batch updating records</h3>
-
-<p>
-To batch update a group of records (for example, to change "NY" to "New York" 
-in all fields), call the <code>{@link 
-android.content.ContentResolver#update ContentResolver.update()}</code> 
-method with the columns and values to change.
-</p>
-
-
-<h3><a name="deletingrecord"></a>Deleting a record</h3>
-
-<p>
-To delete a single record, call {<code>{@link 
-android.content.ContentResolver#delete ContentResolver.delete()}</code> 
-with the URI of a specific row.
-</p>
-
-<p>
-To delete multiple rows, call <code>{@link 
-android.content.ContentResolver#delete ContentResolver.delete()}</code> 
-with the URI of the type of record to delete (for example, {@code android.provider.Contacts.People.CONTENT_URI}) and an SQL {@code WHERE} 
-clause defining which rows to delete.  (<i><b>Caution</b>: 
-Be sure to include a valid {@code WHERE} clause if you're deleting a general 
-type, or you risk deleting more records than you intended!</i>).
-</p>
-
-
-<h2><a name="creating"></a>Creating a Content Provider</h2>
-
-<p>
-To create a content provider, you must:
-</p>
-
-<ul>
-<li>Set up a system for storing the data.  Most content providers 
-store their data using Android's file storage methods or SQLite databases, 
-but you can store your data any way you want.  Android provides the
-{@link android.database.sqlite.SQLiteOpenHelper SQLiteOpenHelper}
-class to help you create a database and {@link 
-android.database.sqlite.SQLiteDatabase SQLiteDatabase} to manage it.</li>
-
-<li><p>Extend the {@link android.content.ContentProvider} class to provide 
-access to the data.</p></li>
-
-<li><p>Declare the content provider in the manifest file for your 
-application (AndroidManifest.xml).</p></li>
-</ul>
-
-<p>
-The following sections have notes on the last two of these tasks.
-</p>
-
-
-<h3>Extending the ContentProvider class</h3>
-
-<p>
-You define a {@link android.content.ContentProvider} subclass to 
-expose your data to others using the conventions expected by 
-ContentResolver and Cursor objects.  Principally, this means 
-implementing six abstract methods declared in the ContentProvider class:
-</p>
-
-<p style="margin-left: 2em">{@code query()}
-<br/>{@code insert()}
-<br/>{@code update()}
-<br/>{@code delete()}
-<br/>{@code getType()}
-<br/>{@code onCreate()}</p>
-
-<p>
-The {@code query()} method must return a {@link android.database.Cursor} object 
-that can iterate over the requested data.  Cursor itself is an interface, but
-Android provides some ready-made Cursor objects that you can use.  For example,
-{@link android.database.sqlite.SQLiteCursor} can iterate over data stored in
-an SQLite database.  You get the Cursor object by calling any of the {@link 
-android.database.sqlite.SQLiteDatabase SQLiteDatabase} class's {@code query()}
-methods.  There are other Cursor implementations &mdash; such as {@link 
-android.database.MatrixCursor} &mdash; for data not stored in a database.
-</p>
-
-<p>
-Because these ContentProvider methods can be called from 
-various ContentResolver objects in different processes and threads, 
-they must be implemented in a thread-safe manner. 
-</p>
-
-<p>
-As a courtesy, you might also want to call <code>{@link android.content.ContentResolver#notifyChange(android.net.Uri,android.database.ContentObserver)
-ContentResolver.notifyChange()}</code> to notify listeners when there are 
-modifications to the data. 
-</p>
-
-<p>
-Beyond defining the subclass itself, there are other steps you should take
-to simplify the work of clients and make the class more accessible: 
-</p>
-
-<ul>
-<li>Define a {@code public static final} {@link android.net.Uri} 
-named {@code CONTENT_URI}.  This is the string that represents the full 
-{@code content:} URI that your content provider handles.  You must define a 
-unique string for this value.  The best solution is to use the fully-qualified 
-class name of the content provider (made lowercase).  So, for example, the 
-URI for a TransportationProvider class could be defined as follows:
-
-<pre>public static final Uri CONTENT_URI = 
-               Uri.parse("content://com.example.codelab.transportationprovider");</pre>
-
-<p>
-If the provider has subtables, also define {@code CONTENT_URI} constants for
-each of the subtables.  These URIs should all have the same authority (since
-that identifies the content provider), and be distinguished only by their paths. 
-For example:
-</p>
-
-<p style="margin-left: 2em">{@code content://com.example.codelab.transportationprovider/train} 
-<br/>{@code content://com.example.codelab.transportationprovider/air/domestic}
-<br/>{@code content://com.example.codelab.transportationprovider/air/international}</p>
-
-<p>
-For an overview of {@code content:} URIs, see the <a href="#urisum">Content URI 
-Summary</a> at the end of this document.
-</p></li>
-
-<li><p>Define the column names that the content provider will return to clients. 
-If you are using an underlying database, these column names are typically 
-identical to the SQL database column names they represent.  Also define
-{@code public static} String constants that clients can use to specify 
-the columns in queries and other instructions.
-</p>
-
-<p>
-Be sure to include an integer column named "{@code _id}" 
-(with the constant {@code _ID}) for 
-the IDs of the records.  You should have this field whether or not you have 
-another field (such as a URL) that is also unique among all records.  If 
-you're using the SQLite database, the {@code _ID} field should be the 
-following type:
-</p>
-
-<p style="margin-left: 2em">{@code INTEGER PRIMARY KEY AUTOINCREMENT}</p>
-
-<p>
-The {@code AUTOINCREMENT} descriptor is optional.  But without it, SQLite
-increments an ID counter field to the next number above the largest
-existing number in the column.  If you delete the last row, the next row added
-will have the same ID as the deleted row.  {@code AUTOINCREMENT} avoids this 
-by having SQLite increment to the next largest value whether deleted or not.
-</p>
-</li>
-
-<li><p>Carefully document the data type of each column.  Clients need this
-information to read the data.</p></li>
-
-<li><p>If you are handling a new data type, you must define a new MIME type 
-to return in your implementation of <code>{@link 
-android.content.ContentProvider#getType ContentProvider.getType()}</code>.  
-The type depends in part on whether or not the {@code content:} URI submitted 
-to {@code getType()} limits the request to a specific record.  There's one 
-form of the MIME type for a single record and another for multiple records.  
-Use the {@link android.net.Uri Uri} methods to help determine what is being 
-requested.  Here is the general format for each type:</p></li>
-
-<ul>
-<li><p>For a single record:&nbsp;&nbsp;&nbsp; {@code vnd.android.cursor.item/vnd.<em>yourcompanyname.contenttype</em>}</p>
-
-<p>For example, a request for train record 122, like this URI,</p>
-<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains/122}</p>
-
-<p>might return this MIME type:</p>
-<p style="margin-left: 2em">{@code vnd.android.cursor.item/vnd.example.rail}</p>
-</li>
-
-<li><p>For multiple records:&nbsp;&nbsp;&nbsp; {@code vnd.android.cursor.dir/vnd.<em>yourcompanyname.contenttype</em>}</p>
-
-<p>For example, a request for all train records, like the following URI,</p>
-<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains}</p>
-
-<p>might return this MIME type:</p>
-<p style="margin-left: 2em">{@code vnd.android.cursor.dir/vnd.example.rail}</p>
-</li>
-</ul>
-
-<li><p>If you are exposing byte data that's too big to put in the table itself
-&mdash; such as a large bitmap file &mdash; the field that exposes the
-data to clients should actually contain a {@code content:} URI string.
-This is the field that gives clients access to the data file.  The record 
-should also have another field, named "{@code _data}" that lists the exact file 
-path on the device for that file.  This field is not intended to be read by 
-the client, but by the ContentResolver.  The client will call <code>{@link 
-android.content.ContentResolver#openInputStream ContentResolver.openInputStream()}</code> 
-on the user-facing field holding the URI for the item.  The ContentResolver 
-will request the "{@code _data}" field for that record, and because
-it has higher permissions than a client, it should be able to access
-that file directly and return a read wrapper for the file to the client.</p></li>
-
-</ul>
-
-<p>
-For an example of a private content provider implementation, see the 
-NodePadProvider class in the Notepad sample application that ships with the SDK.
-</p>
-
-
-<h3>Declaring the content provider</h3>
-
-<p>
-To let the Android system know about the content provider you've developed, 
-declare it with a {@code &lt;provider&gt;} element in the application's 
-AndroidManifest.xml file.  Content providers that are not declared in the
-manifest are not visible to the Android system
-</p>
-
-<p>
-The {@code name} attribute is the fully qualified name of the ContentProvider
-subclass.  The {@code authorities} attribute is the authority part of the 
-{@code content:} URI that identifies the provider.
-For example if the ContentProvider subclass is AutoInfoProvider, the 
-{@code &lt;provider&gt;} element might look like this:
-</p>
-
-<pre>
-&lt;provider android:name="com.example.autos.AutoInfoProvider"
-          android:authorities="com.example.autos.autoinfoprovider" 
-          . . . /&gt
-&lt;/provider&gt;
-</pre>
-
-<p>
-Note that the {@code authorities} attribute omits the path part of a 
-{@code content:} URI.  For example, if AutoInfoProvider controlled subtables
-for different types of autos or different manufacturers,
-</p>
-
-<p style="margin-left: 2em">{@code content://com.example.autos.autoinfoprovider/honda}
-<br/>{@code content://com.example.autos.autoinfoprovider/gm/compact}
-<br/>{@code content://com.example.autos.autoinfoprovider/gm/suv}</p>
-
-<p>
-those paths would not be declared in the manifest.  The authority is what 
-identifies the provider, not the path; your provider can interpret the path 
-part of the URI in any way you choose.
-</p>
-
-<p>
-Other {@code &lt;provider&gt;} attributes can set permissions to read and 
-write data, provide for an icon and text that can be displayed to users, 
-enable and disable the provider, and so on.  Set the {@code multiprocess} 
-attribute to "{@code true}" if data does not need to be synchronized between 
-multiple running versions of the content provider.  This permits an instance 
-of the provider to be created in each client process, eliminating the need 
-to perform IPC. 
-</p>
-
-
-<h2><a name="urisum"></a>Content URI Summary</h2>
-
-<p>
-Here is a recap of the important parts of a content URI:
-</p>
-
-<p>
-<img src="{@docRoot}images/content_uri.png" alt="Elements of a content URI" 
-height="80" width="528">
-</p>
-
-<ol type="A">
-<li>Standard prefix indicating that the data is controlled by a
-content provider. It's never modified.</li>
-
-<li><p>The authority part of the URI; it identifies the content provider. 
-For third-party applications, this should be a fully-qualified class name 
-(reduced to lowercase) to ensure uniqueness.  The authority is declared in 
-the {@code &lt;provider&gt;} element's {@code authorities} attribute:</p>
-
-<pre>&lt;provider android:name=".TransportationProvider"
-          android:authorities="com.example.transportationprovider"
-          . . .  &gt;</pre></li>
-
-<li><p>The path that the content provider uses to determine what kind of data is
-being requested.  This can be zero or more segments long.  If the content provider
-exposes only one type of data (only trains, for example), it can be absent.
-If the provider exposes several types, including subtypes, it can be several 
-segments long &mdash; for example, "{@code land/bus}", "{@code land/train}", 
-"{@code sea/ship}", and "{@code sea/submarine}" to give four possibilities.</p></li>
-
-<li><p>The ID of the specific record being requested, if any.  This is the 
-{@code _ID} value of the requested record.  If the request is not limited to
-a single record, this segment and the trailing slash are omitted:</p>
-
-<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains}</p>
-</li>
-</ol>
-
-
+<dl>
+    <dt>
+        <strong><a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+        Content Provider Basics</a></strong>
+    </dt>
+    <dd>
+        How to access data in a content provider when the data is organized in tables.
+    </dd>
+    <dt>
+        <strong><a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+        Creating a Content Provider</a></strong>
+    </dt>
+    <dd>
+        How to create your own content provider.
+    </dd>
+    <dt>
+        <strong><a href="{@docRoot}guide/topics/providers/calendar-provider.html">
+        Calendar Provider</a></strong>
+    </dt>
+    <dd>
+        How to access the Calendar Provider that is part of the Android platform.
+    </dd>
+</dl>
diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
index 80de9f9..a34ed6c 100644
--- a/docs/html/guide/topics/resources/drawable-resource.jd
+++ b/docs/html/guide/topics/resources/drawable-resource.jd
@@ -1248,7 +1248,6 @@
     android:drawable="@drawable/android"
     android:clipOrientation="horizontal"
     android:gravity="left" /&gt;
-&lt;/clip>
 </pre>
     <p>The following layout XML applies the clip drawable to a View:</p>
 <pre>
diff --git a/docs/html/guide/topics/resources/more-resources.jd b/docs/html/guide/topics/resources/more-resources.jd
index 972eab9..d37b9f8 100644
--- a/docs/html/guide/topics/resources/more-resources.jd
+++ b/docs/html/guide/topics/resources/more-resources.jd
@@ -216,27 +216,29 @@
 For example: 10px, 2in, 5sp. The following units of measure are supported by Android:</p>
 <dl>
   <dt>{@code dp}</dt>
-    <dd>Density-independent Pixels - an abstract unit that is based on the physical density of the
-screen. These units are relative to a 160 dpi (dots per inch) screen, so <em>{@code 160dp} is
-always one inch</em> regardless of the screen density. The ratio of dp-to-pixel will change with the
-screen density, but not necessarily in direct proportion. You should use these units when specifying
-view dimensions in your layout, so the UI properly scales to render at the same actual size on
-different screens. (The compiler accepts both "dip" and "dp", though "dp" is more consistent with
-"sp".)</dd>
+    <dd>Density-independent Pixels - An abstract unit that is based on the physical density of the
+screen. These units are relative to a 160 dpi (dots per inch) screen, on which 1dp is roughly equal
+to 1px. When running on a higher density screen, the number of pixels used to draw 1dp is scaled up
+by a factor appropriate for the screen's dpi. Likewise, when on a lower density screen, the number
+of pixels used for 1dp is scaled down. The ratio of dp-to-pixel will change with the screen density,
+but not necessarily in direct proportion. Using dp units (instead of px units) is a simple solution
+to making the view dimensions in your layout resize properly for different screen densities. In
+other words, it provides consistency for the real-world sizes of your UI elements across different
+devices.</dd>
   <dt>{@code sp}</dt>
-    <dd>Scale-independent Pixels - this is like the dp unit, but it is also scaled by the user's font
+    <dd>Scale-independent Pixels - This is like the dp unit, but it is also scaled by the user's font
     size preference. It is recommend you use this unit when specifying font sizes, so they will be adjusted
     for both the screen density and the user's preference.</dd>
   <dt>{@code pt}</dt>
     <dd>Points - 1/72 of an inch based on the physical size of the screen.</dd>
   <dt>{@code px}</dt>
-    <dd>Pixels - corresponds to actual pixels on the screen. This unit of measure is not recommended because
+    <dd>Pixels - Corresponds to actual pixels on the screen. This unit of measure is not recommended because
     the actual representation can vary across devices; each devices may have a different number of pixels
     per inch and may have more or fewer total pixels available on the screen.</dd>
   <dt>{@code mm}</dt>
-    <dd>Millimeters - based on the physical size of the screen.</dd>
+    <dd>Millimeters - Based on the physical size of the screen.</dd>
   <dt>{@code in}</dt>
-    <dd>Inches - based on the physical size of the screen.</dd>
+    <dd>Inches - Based on the physical size of the screen.</dd>
 </dl>
 
 <p class="note"><strong>Note:</strong> A dimension is a simple resource that is referenced
diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
index e06563d..8b8e75b 100644
--- a/docs/html/guide/topics/search/search-dialog.jd
+++ b/docs/html/guide/topics/search/search-dialog.jd
@@ -544,7 +544,8 @@
 }
 </pre>
 
-<p>If the user cancels search by pressing the BACK button, the search dialog closes and the activity
+<p>If the user cancels search by pressing the <em>Back</em> button, the search dialog closes and the
+activity
 regains input focus. You can register to be notified when the search dialog is
 closed with {@link android.app.SearchManager#setOnDismissListener(SearchManager.OnDismissListener)
 setOnDismissListener()}
@@ -569,7 +570,8 @@
 android.content.Intent#ACTION_SEARCH} intent with a call to {@link
 android.app.Activity#onCreate(Bundle) onCreate()} and a new instance of the
 activity is brought to the top of the activity stack. There are now two instances of your
-searchable activity in the activity stack (so pressing the BACK button goes back to the previous
+searchable activity in the activity stack (so pressing the <em>Back</em> button goes back to the
+previous
 instance of the searchable activity, rather than exiting the searchable activity).</li>
   <li>If you set {@code android:launchMode} to <code>"singleTop"</code>, then the
 searchable activity receives the {@link android.content.Intent#ACTION_SEARCH} intent with a call
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index b83bde7..e59fa0f 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -113,9 +113,10 @@
 href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a> directly in the action bar,
 as "action items." Action items can also provide an "action view," which provides an embedded
 widget for even more immediate action behaviors. Menu items that are not promoted
-to an action item are available in the overflow menu, revealed by either the device MENU button
+to an action item are available in the overflow menu, revealed by either the device <em>Menu</em>
+button
 (when available) or by an "overflow menu" button in the action bar (when the device does not
-include a MENU button).</p>
+include a <em>Menu</em> button).</p>
 </li>
 </ul>
 
@@ -125,6 +126,10 @@
 landscape handset), showing the logo on the left, navigation tabs, and an action item on the
 right (plus the overflow menu button).</p>
 
+<p class="note"><strong>Note:</strong> If you're looking for information about the contextual
+action bar for displaying contextual action items, see the <a
+href="{@docRoot}guide/topics/ui/menus.html#context-menu">Menu</a> guide.</p>
+
 
 <div class="design-announce">
 <p><strong>Action Bar Design</strong></p>
@@ -225,9 +230,10 @@
 href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a>. To do this, you can
 declare that the menu item should appear in the action bar as an "action item." An action item can
 include an icon and/or a text title. If a menu item does not appear as an action item, then the
-system places it in the overflow menu. The overflow menu is revealed either by the device MENU
+system places it in the overflow menu. The overflow menu is revealed either by the device
+<em>Menu</em>
 button (if provided by the device) or an additional button in the action bar (if the device does not
-provide the MENU button).</p>
+provide the <em>Menu</em> button).</p>
 
 <div class="figure" style="width:359px">
   <img src="{@docRoot}images/ui/actionbar-item-withtext.png" height="57" alt="" />
@@ -1421,7 +1427,7 @@
     &lt;/style>
 
     &lt;!-- style for the action bar tab text -->
-    &lt;style name="CustomTabTextStyle">
+    &lt;style name="CustomTabTextStyle" parent="@android:style/TextAppearance.Holo">
         &lt;item name="android:textColor">#2456c2&lt;/item>
     &lt;/style>
 &lt;/resources>
@@ -1437,8 +1443,7 @@
 manifest file like this:</p>
 
 <pre>
-&lt;application android:theme="&#64;style/CustomActivityTheme"
-             ... />
+&lt;application android:theme="&#64;style/CustomActivityTheme" ... />
 </pre>
 
 <p>For more information about using style and theme resources in your application, read <a
@@ -1457,7 +1462,7 @@
 parent action bar style such as {@link android.R.style#Widget_Holo_ActionBar
 Widget.Holo.ActionBar}.</p>
 
-<p>For example, if you want to change the action bar's background, you could use the following
+<p>For example, if you want to change the action bar's background, you can use the following
 styles:</p>
 
 <pre>
@@ -1465,14 +1470,15 @@
 &lt;resources>
     &lt;!-- the theme applied to the application or activity -->
     &lt;style name="CustomActivityTheme" parent="@android:style/Theme.Holo">
-        &lt;item name="android:actionBarTabTextStyle">@style/customTabTextStyle&lt;/item>
+        &lt;item name="android:actionBarStyle">@style/MyActionBar&lt;/item>
         &lt;!-- other activity and action bar styles here -->
     &lt;/style>
 
-    &lt;!-- style for the action bar, simply to change the background -->
-    &lt;style parent="@android:style/Widget.Holo.ActionBar">
+    &lt;!-- style for the action bar backgrounds -->
+    &lt;style name="MyActionBar" parent="@android:style/Widget.Holo.ActionBar">
         &lt;item name="android:background">@drawable/ab_background&lt;/item>
-        &lt;item name="android:backgroundSplit">@drawable/ab_background&lt;/item>
+        &lt;item name="android:backgroundStacked">@drawable/ab_background&lt;/item>
+        &lt;item name="android:backgroundSplit">@drawable/ab_split_background&lt;/item>
     &lt;/style>
 &lt;/resources>
 </pre>
diff --git a/docs/html/guide/topics/ui/how-android-draws.jd b/docs/html/guide/topics/ui/how-android-draws.jd
index 3a57afa..6a8cd86 100644
--- a/docs/html/guide/topics/ui/how-android-draws.jd
+++ b/docs/html/guide/topics/ui/how-android-draws.jd
@@ -62,7 +62,7 @@
 
    <p>
    The measure pass uses two classes to communicate dimensions. The
-   {@link android.view.View.MeasureSpec} class is used by Views to tell their parents how they
+   {@link android.view.ViewGroup.LayoutParams} class is used by Views to tell their parents how they
    want to be measured and positioned. The base LayoutParams class just
    describes how big the View wants to be for both width and height. For each
    dimension, it can specify one of:</p>
diff --git a/docs/html/guide/topics/ui/index.jd b/docs/html/guide/topics/ui/index.jd
index d3060c5..83c8150 100644
--- a/docs/html/guide/topics/ui/index.jd
+++ b/docs/html/guide/topics/ui/index.jd
@@ -174,7 +174,8 @@
 
 <p>Application menus are another important part of an application's UI. Menus offers a reliable interface that reveals
 application functions and settings. The most common application menu is revealed by pressing
-the MENU key on the device. However, you can also add Context Menus, which may be revealed when the user presses
+the <em>Menu</em> button on the device. However, you can also add Context Menus, which may be
+revealed when the user presses
 and holds down on an item.</p>
 
 <p>Menus are also structured using a View hierarchy, but you don't define this structure yourself. Instead,
diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd
index 7b5b3dc..d51a378 100644
--- a/docs/html/guide/topics/ui/menus.jd
+++ b/docs/html/guide/topics/ui/menus.jd
@@ -6,77 +6,129 @@
 <div id="qv-wrapper">
 <div id="qv">
   <h2>In this document</h2>
-  <ol>
-    <li><a href="#xml">Creating a Menu Resource</a></li>
-    <li><a href="#Inflating">Inflating a Menu Resource</a>
-    <li><a href="#options-menu">Creating an Options Menu</a>
-      <ol>
-        <li><a href="#ChangingTheMenu">Changing menu items at runtime</a></li>
-      </ol>
-    </li>
-    <li><a href="#context-menu">Creating a Context Menu</a></li>
-    <li><a href="#submenu">Creating a Submenu</a></li>
-    <li><a href="#features">Other Menu Features</a>
-      <ol>
-        <li><a href="#groups">Menu groups</a></li>
-        <li><a href="#checkable">Checkable menu items</a></li>
-        <li><a href="#shortcuts">Shortcut keys</a></li>
-        <li><a href="#intents">Dynamically adding menu intents</a></li>
-      </ol>
-    </li>
-  </ol>
+<ol>
+  <li><a href="#xml">Defining a Menu in XML</a></li>
+  <li><a href="#options-menu">Creating an Options Menu</a>
+    <ol>
+      <li><a href="#RespondingOptionsMenu">Handling click events</a></li>
+      <li><a href="#ChangingTheMenu">Changing menu items at runtime</a></li>
+    </ol>
+  </li>
+  <li><a href="#context-menu">Creating Contextual Menus</a>
+    <ol>
+      <li><a href="#FloatingContextMenu">Creating a floating context menu</a></li>
+      <li><a href="#CAB">Using the contextual action mode</a></li>
+    </ol>
+  </li>
+  <li><a href="#PopupMenu">Creating a Popup Menu</a>
+    <ol>
+      <li><a href="#PopupEvents">Handling click events</a></li>
+    </ol>
+  </li>
+  <li><a href="#groups">Creating Menu Groups</a>
+    <ol>
+      <li><a href="#checkable">Using checkable menu items</a></li>
+    </ol>
+  </li>
+  <li><a href="#intents">Adding Menu Items Based on an Intent</a>
+    <ol>
+      <li><a href="#AllowingToAdd">Allowing your activity to be added to other menus</a></li>
+    </ol>
+  </li>
+</ol>
 
   <h2>Key classes</h2>
   <ol>
     <li>{@link android.view.Menu}</li>
     <li>{@link android.view.MenuItem}</li>
     <li>{@link android.view.ContextMenu}</li>
-    <li>{@link android.view.SubMenu}</li>
+    <li>{@link android.view.ActionMode}</li>
   </ol>
 
   <h2>See also</h2>
   <ol>
     <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
     <li><a href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a></li>
+    <li><a
+href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">Say
+Goodbye to the Menu Button</a></li>
   </ol>
 </div>
 </div>
 
-<p>Menus are an important part of an activity's user interface, which provide users a familiar
-way to perform actions. Android offers a simple framework for you to add standard
-menus to your application.</p>
+<p>Menus are a common user interface component in many types of applications. To provide a familiar
+and consistent user experience, you should use the {@link android.view.Menu} APIs to present user
+actions and other options in your activities.</p>
 
-<p>There are three types of application menus:</p>
+<p>Beginning with Android 3.0 (API level 11), Android-powered devices are no longer required to
+provide a dedicated <em>Menu</em> button. With this change, Android apps should migrate away from a
+dependence on the traditional 6-item menu panel and instead provide an action bar to present common
+user actions.</p>
+
+<p>Although the design and user experience for some menu items have changed, the semantics to define
+a set of actions and options is still based on the {@link android.view.Menu} APIs. This
+guide shows how to create the three fundamental types of menus or action presentations on all
+versions of Android:</p>
+
 <dl>
-  <dt><strong>Options Menu</strong></dt>
-    <dd>The primary collection of menu items for an activity, which appears when the user touches
-the MENU button. When your application is running on Android 3.0 or later, you can provide
-quick access to select menu items by placing them directly in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>, as "action items."</dd>
-  <dt><strong>Context Menu</strong></dt>
-    <dd>A floating list of menu items that appears when the user touches and holds a view
-that's registered to provide a context menu.
+  <dt><strong>Options menu and action bar</strong></dt>
+    <dd>The <a href="#options-menu">options menu</a> is the primary collection of menu items for an
+activity. It's where you should place actions that have a global impact on the app, such as
+"Search," "Compose email," and "Settings."
+  <p>If you're developing for Android 2.3 or lower, users can
+reveal the options menu panel by pressing the <em>Menu</em> button.</p>
+  <p>On Android 3.0 and higher, items from the options menu are presented by the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a> as a combination of on-screen action
+items and overflow options. Beginning with Android 3.0, the <em>Menu</em> button is deprecated (some
+devices
+don't have one), so you should migrate toward using the action bar to provide access to actions and
+other options.</p>
+  <p>See the section about <a href="#options-menu">Creating an Options Menu</a>.</p>
+    </dd>
+    
+  <dt><strong>Context menu and contextual action mode</strong></dt>
+  
+   <dd>A context menu is a <a href="#FloatingContextMenu">floating menu</a> that appears when the
+user performs a long-click on an element. It provides actions that affect the selected content or
+context frame.
+  <p>When developing for Android 3.0 and higher, you should instead use the <a
+href="#CAB">contextual action mode</a> to enable actions on selected content. This mode displays
+action items that affect the selected content in a bar at the top of the screen and allows the user
+to select multiple items.</p>
+  <p>See the section about <a href="#context-menu">Creating Contextual Menus</a>.</p>
 </dd>
-  <dt><strong>Submenu</strong></dt>
-    <dd>A floating list of menu items that appears when the user touches a menu item that contains
-a nested menu.</dd>
+    
+  <dt><strong>Popup menu</strong></dt>
+    <dd>A popup menu displays a list of items in a vertical list that's anchored to the view that
+invoked the menu. It's good for providing an overflow of actions that relate to specific content or
+to provide options for a second part of a command. Actions in a popup menu should
+<strong>not</strong> directly affect the corresponding content&mdash;that's what contextual actions
+are for. Rather, the popup menu is for extended actions that relate to regions of content in your
+activity.
+  <p>See the section about <a href="#PopupMenu">Creating a Popup Menu</a>.</p>
+</dd>
 </dl>
 
-<p>This document shows you how to create each type of menu, using XML to define the content of
-the menu and callback methods in your activity to respond when the user selects an item.</p>
 
 
+<h2 id="xml">Defining a Menu in XML</h2>
 
-<h2 id="xml">Creating a Menu Resource</h2>
+<p>For all menu types, Android provides a standard XML format to define menu items.
+Instead of building a menu in your activity's code, you should define a menu and all its items in an
+XML <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. You can then
+inflate the menu resource (load it as a {@link android.view.Menu} object) in your activity or
+fragment.</p>
 
-<p>Instead of instantiating a {@link android.view.Menu} in your application code, you should
-define a menu and all its items in an XML <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>, then inflate the menu
-resource (load it as a programmable object) in your application code. Using a menu resource to
-define your menu is a good practice because it separates the content for the menu from your
-application code. It's also easier to visualize the structure and content of a menu in XML.</p>
+<p>Using a menu resource is a good practice for a few reasons:</p>
+<ul>
+  <li>It's easier to visualize the menu structure in XML.</li>
+  <li>It separates the content for the menu from your application's behavioral code.</li>
+  <li>It allows you to create alternative menu configurations for different platform versions,
+screen sizes, and other configurations by leveraging the <a
+href="{@docRoot}guide/topics/resources/index.html">app resources</a> framework.</li>
+</ul>
 
-<p>To create a menu resource, create an XML file inside your project's <code>res/menu/</code>
+<p>To define the menu, create an XML file inside your project's <code>res/menu/</code>
 directory and build the menu with the following elements:</p>
 <dl>
   <dt><code>&lt;menu></code></dt>
@@ -90,8 +142,8 @@
     
   <dt><code>&lt;group></code></dt>
     <dd>An optional, invisible container for {@code &lt;item&gt;} elements. It allows you to
-categorize menu items so they share properties such as active state and visibility. See the
-section about <a href="#groups">Menu groups</a>.</dd>
+categorize menu items so they share properties such as active state and visibility. For more
+information, see the section about <a href="#groups">Creating Menu Groups</a>.</dd>
 </dl>
 
 
@@ -101,14 +153,17 @@
 &lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
     &lt;item android:id="@+id/new_game"
           android:icon="@drawable/ic_new_game"
-          android:title="@string/new_game" /&gt;
+          android:title="@string/new_game"
+          android:showAsAction="ifRoom"/&gt;
     &lt;item android:id="@+id/help"
           android:icon="@drawable/ic_help"
           android:title="@string/help" /&gt;
 &lt;/menu&gt;
 </pre>
 
-<p>This example defines a menu with two items. Each item includes the attributes:</p>
+<p>The <code>&lt;item></code> element supports several attributes you can use to define an item's
+appearance and behavior. The items in the above menu include the following attributes:</p>
+
 <dl>
   <dt>{@code android:id}</dt>
     <dd>A resource ID that's unique to the item, which allows the application can recognize the item
@@ -117,312 +172,24 @@
     <dd>A reference to a drawable to use as the item's icon.</dd>
   <dt>{@code android:title}</dt>
     <dd>A reference to a string to use as the item's title.</dd>
+  <dt>{@code android:showAsAction}</dt>
+    <dd>Specifies when and how this item should appear as an action item in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>.</dd>
 </dl>
 
-<p>There are many more attributes you can include in an {@code &lt;item&gt;}, including some that
- specify how the item may appear in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>. For more information about the XML
-syntax and attributes for a menu resource, see the <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> reference.</p>
+<p>These are the most important attributes you should use, but there are many more available.
+For information about all the supported attributes, see the <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> document.</p>
 
-
-
-<h2 id="Inflating">Inflating a Menu Resource</h2>
-
-<p>From your application code, you can inflate a menu resource (convert the XML resource into a
-programmable object) using
-{@link android.view.MenuInflater#inflate(int,Menu) MenuInflater.inflate()}. For
-example, the following code inflates the <code>game_menu.xml</code> file defined above, during the
-{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} callback method, to
-use the menu as the activity's Options Menu:</p>
-
-<pre>
-&#64;Override
-public boolean onCreateOptionsMenu(Menu menu) {
-    MenuInflater inflater = getMenuInflater();
-    inflater.inflate(R.menu.game_menu, menu);
-    return true;
-}
-</pre>
-
-<p>The {@link android.app.Activity#getMenuInflater()} method returns a {@link
-android.view.MenuInflater} for the activity. With this object, you can call {@link
-android.view.MenuInflater#inflate(int,Menu) inflate()}, which inflates a menu resource into a
-{@link android.view.Menu} object. In this example, the menu resource defined by
-<code>game_menu.xml</code>
-is inflated into the {@link android.view.Menu} that was passed into {@link
-android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}. (This callback method for
-the Options Menu is discussed more in the next section.)</p>
-
-
-
-<h2 id="options-menu">Creating an Options Menu</h2>
-
-<div class="figure" style="width:200px">
-  <img src="{@docRoot}images/options_menu.png" height="333" alt="" />
-  <p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Options Menu in the
-Browser.</p>
-</div>
-
-<p>The Options Menu is where you should include basic activity actions and necessary navigation
-items (for example, a button to open the application settings). Items in the Options Menu are
-accessible in two distinct ways: the MENU button or in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> (on devices running Android 3.0
-or higher).</p>
-
-<p>When running on a device with Android 2.3 and lower, the Options Menu appears at the bottom of
-the screen, as shown in figure 1. When opened, the first visible portion of the Options Menu is
-the icon menu. It holds the first six menu items. If you add more than six items to the
-Options Menu, Android places the sixth item and those after it into the overflow menu, which the
-user can open by touching the "More" menu item.</p>
-
-<p>On Android 3.0 and higher, items from the Options Menu is placed in the Action Bar, which appears
-at the top of the activity in place of the traditional title bar. By default all items from the
-Options Menu are placed in the overflow menu, which the user can open by touching the menu icon
-on the right side of the Action Bar. However, you can place select menu items directly in the
-Action Bar as "action items," for instant access, as shown in figure 2.</p>
-
-<p>When the Android system creates the Options Menu for the first time, it calls your
-activity's {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} method. Override this method in your activity
-and populate the {@link android.view.Menu} that is passed into the method,
-{@link android.view.Menu} by inflating a menu resource as described above in <a
-href="#Inflating">Inflating a Menu Resource</a>. For example:</p>
-
-<pre>
-&#64;Override
-public boolean onCreateOptionsMenu(Menu menu) {
-    MenuInflater inflater = getMenuInflater();
-    inflater.inflate(R.menu.game_menu, menu);
-    return true;
-}
-</pre>
-
-<div class="figure" style="width:450px">
-<img src="{@docRoot}images/ui/actionbar.png" alt="" />
-<p class="img-caption"><strong>Figure 2.</strong> Action bar from the <a
-href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> app, including
-navigation tabs and a camera action item (plus the overflow menu button).</p>
-</div>
-
-<p>You can also populate the menu in code, using {@link android.view.Menu#add(int,int,int,int)
-add()} to add items to the {@link android.view.Menu}.</p>
-
-<p class="note"><strong>Note:</strong> On Android 2.3 and lower, the system calls {@link
-android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} to create the Options Menu
-when the user opens it for the first time, but on Android 3.0 and greater, the system creates it as
-soon as the activity is created, in order to populate the Action Bar.</p>
-
-
-<h3 id="RespondingOptionsMenu">Responding to user action</h3>
-
-<p>When the user selects a menu item from the Options Menu (including action items in the
-Action Bar), the system calls your activity's
-{@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}
-method. This method passes the
-{@link android.view.MenuItem} that the user selected. You can identify the menu item by calling
-{@link android.view.MenuItem#getItemId()}, which returns the unique ID for the menu
-item (defined by the {@code android:id} attribute in the menu resource or with an integer
-given to the {@link android.view.Menu#add(int,int,int,int) add()} method). You can match this ID
-against known menu items and perform the appropriate action. For example:</p>
-
-<pre>
-&#64;Override
-public boolean onOptionsItemSelected(MenuItem item) {
-    // Handle item selection
-    switch (item.getItemId()) {
-    case R.id.new_game:
-        newGame();
-        return true;
-    case R.id.help:
-        showHelp();
-        return true;
-    default:
-        return super.onOptionsItemSelected(item);
-    }
-}
-</pre>
-
-<p>In this example, {@link android.view.MenuItem#getItemId()} queries the ID for the selected menu
-item and the switch statement compares the ID against the resource IDs that were assigned to menu
-items in the XML resource. When a switch case successfully handles the menu item, it
-returns {@code true} to indicate that the item selection was handled. Otherwise, the default
-statement passes the menu item to the super class, in
-case it can handle the item selected. (If you've directly extended the {@link android.app.Activity}
-class, then the super class returns {@code false}, but it's a good practice to
-pass unhandled menu items to the super class instead of directly returning {@code false}.)</p>
-
-<p>Additionally, Android 3.0 adds the ability for you to define the on-click behavior for a menu
-item in the <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> XML,
-using the {@code android:onClick} attribute. So you don't need to implement {@link
-android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}. Using the {@code
-android:onClick} attribute, you can specify a method to call when the user selects the menu item.
-Your activity must then implement the method specified in the {@code android:onClick} attribute so 
-that it accepts a single {@link android.view.MenuItem} parameter&mdash;when the system calls this
-method, it passes the menu item selected.</p>
-
-<p class="note"><strong>Tip:</strong> If your application contains multiple activities and
-some of them provide the same Options Menu, consider creating
-an activity that implements nothing except the {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} and {@link android.app.Activity#onOptionsItemSelected(MenuItem)
-onOptionsItemSelected()} methods. Then extend this class for each activity that should share the
-same Options Menu. This way, you have to manage only one set of code for handling menu
-actions and each descendant class inherits the menu behaviors.<br/><br/>
-If you want to add menu items to one of your descendant activities,
-override {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} in that activity. Call {@code super.onCreateOptionsMenu(menu)} so the
-original menu items are created, then add new menu items with {@link
-android.view.Menu#add(int,int,int,int) menu.add()}. You can also override the super class's
-behavior for individual menu items.</p>
-
-
-<h3 id="ChangingTheMenu">Changing menu items at runtime</h3>
-
-<p>Once the activity is created, the {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} method is
-called only once, as described above. The system keeps and re-uses the {@link
-android.view.Menu} you define in this method until your activity is destroyed. If you want to change
-the Options Menu any time after it's first created, you must override the
-{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} method. This passes
-you the {@link android.view.Menu} object as it currently exists. This is useful if you'd like to
-remove, add, disable, or enable menu items depending on the current state of your application.</p>
-
-<p>On Android 2.3 and lower, the system calls {@link android.app.Activity#onPrepareOptionsMenu(Menu)
-onPrepareOptionsMenu()} each time the user opens the Options Menu.</p>
-
-<p>On Android 3.0 and higher, you must call {@link android.app.Activity#invalidateOptionsMenu
-invalidateOptionsMenu()} when you want to update the menu, because the menu is always open. The
-system will then call {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}
-so you can update the menu items.</p>
-
-<p class="note"><strong>Note:</strong> 
-You should never change items in the Options Menu based on the {@link android.view.View} currently
-in focus. When in touch mode (when the user is not using a trackball or d-pad), views
-cannot take focus, so you should never use focus as the basis for modifying
-items in the Options Menu. If you want to provide menu items that are context-sensitive to a {@link
-android.view.View}, use a <a href="#context-menu">Context Menu</a>.</p>
-
-<p>If you're developing for Android 3.0 or higher, be sure to also read the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> developer guide.</p>
-
-
-
-
-<h2 id="context-menu">Creating a Context Menu</h2>
-
-<p>A context menu is conceptually similar to the menu displayed when the user performs a
-"right-click" on a PC. You should use a context menu to provide the user access to
-actions that pertain to a specific item in the user interface. On Android, a context menu is
-displayed when the user performs a "long press" (press and hold) on an item.</p>
-
-<p>You can create a context menu for any View, though context menus are most often used for items in
-a {@link android.widget.ListView}. When the user performs a long-press on an item in a ListView and
-the list is registered to provide a context menu, the list item signals to the user that a context
-menu is available by animating its background color&mdash;it transitions from
-orange to white before opening the context menu. (The Contacts application demonstrates this
-feature.)</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h3>Register a ListView</h3>
-<p>If your activity uses a {@link android.widget.ListView} and
-you want all list items to provide a context menu, register all items for a context
-menu by passing the {@link android.widget.ListView} to {@link
-android.app.Activity#registerForContextMenu(View) registerForContextMenu()}. For
-example, if you're using a {@link android.app.ListActivity}, register all list items like this:</p>
-<p><code>registerForContextMenu({@link android.app.ListActivity#getListView()});</code></p>
-</div>
-</div>
-
-<p>In order for a View to provide a context menu, you must "register" the view for a context
-menu. Call {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} and
-pass it the {@link android.view.View} you want to give a context menu. When this View then
-receives a long-press, it displays a context menu.</p>
-
-<p>To define the context menu's appearance and behavior, override your activity's context menu
-callback methods, {@link android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
-onCreateContextMenu()} and
-{@link android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}.</p>
-
-<p>For example, here's an {@link
-android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
-onCreateContextMenu()} that uses the {@code context_menu.xml} menu resource:</p>
-<pre>
-&#64;Override
-public void onCreateContextMenu(ContextMenu menu, View v,
-                                ContextMenuInfo menuInfo) {
-  super.onCreateContextMenu(menu, v, menuInfo);
-  MenuInflater inflater = getMenuInflater();
-  inflater.inflate(R.menu.context_menu, menu);
-}
-</pre>
-
-<p>{@link android.view.MenuInflater} is used to inflate the context menu from a <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. (You can also use
-{@link android.view.Menu#add(int,int,int,int) add()} to add menu items.) The callback method
-parameters include the {@link android.view.View}
-that the user selected and a {@link android.view.ContextMenu.ContextMenuInfo} object that provides
-additional information about the item selected. You might use these parameters to determine
-which context menu should be created, but in this example, all context menus for the activity are
-the same.</p>
-
-<p>Then when the user selects an item from the context menu, the system calls {@link
-android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}. Here is an example
-of how you can handle selected items:</p>
-
-<pre>
-&#64;Override
-public boolean onContextItemSelected(MenuItem item) {
-  AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
-  switch (item.getItemId()) {
-  case R.id.edit:
-    editNote(info.id);
-    return true;
-  case R.id.delete:
-    deleteNote(info.id);
-    return true;
-  default:
-    return super.onContextItemSelected(item);
-  }
-}
-</pre>
-
-<p>The structure of this code is similar to the example for <a href="#options-menu">Creating an
-Options Menu</a>, in which {@link android.view.MenuItem#getItemId()} queries the ID for the selected
-menu item and a switch statement matches the item to the IDs that are defined in the menu resource.
-And like the options menu example, the default statement calls the super class in case it
-can handle menu items not handled here, if necessary.</p>
-
-<p>In this example, the selected item is an item from a {@link android.widget.ListView}. To
-perform an action on the selected item, the application needs to know the list
-ID for the selected item (it's position in the ListView). To get the ID, the application calls
-{@link android.view.MenuItem#getMenuInfo()}, which returns a {@link
-android.widget.AdapterView.AdapterContextMenuInfo} object that includes the list ID for the
-selected item in the {@link android.widget.AdapterView.AdapterContextMenuInfo#id id} field. The
-local methods <code>editNote()</code> and <code>deleteNote()</code> methods accept this list ID to
-perform an action on the data specified by the list ID.</p>
-
-<p class="note"><strong>Note:</strong> Items in a context menu do not support icons or shortcut
-keys.</p>
-
-
-
-<h2 id="submenu">Creating Submenus</h2>
-
-<p>A submenu is a menu that the user can open by selecting an item in another menu. You can add a
-submenu to any menu (except a submenu). Submenus are useful when your application has a lot of
-functions that can be organized into topics, like items in a PC application's menu bar (File, Edit,
-View, etc.).</p>
-
-<p>When creating your <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu
-resource</a>, you can create a submenu by adding a {@code &lt;menu&gt;} element as the child of an
-{@code &lt;item&gt;}. For example:</p>
+<p>You can add a submenu to an item in any menu (except a submenu) by adding a {@code &lt;menu&gt;}
+element as the child of an {@code &lt;item&gt;}. Submenus are useful when your application has a lot
+of functions that can be organized into topics, like items in a PC application's menu bar (File,
+Edit, View, etc.). For example:</p>
 
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?&gt;
 &lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
     &lt;item android:id="@+id/file"
-          android:icon="@drawable/file"
           android:title="@string/file" &gt;
         &lt;!-- "file" submenu --&gt;
         &lt;menu&gt;
@@ -435,23 +202,625 @@
 &lt;/menu&gt;
 </pre>
 
-<p>When the user selects an item from a submenu, the parent menu's respective on-item-selected
-callback method receives the event. For instance, if the above menu is applied as an Options Menu,
-then the {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method
-is called when a submenu item is selected.</p>
-
-<p>You can also use {@link android.view.Menu#addSubMenu(int,int,int,int) addSubMenu()} to
-dynamically add a {@link android.view.SubMenu} to an existing {@link android.view.Menu}. This
-returns the new {@link android.view.SubMenu} object, to which you can add
-submenu items, using {@link android.view.Menu#add(int,int,int,int) add()}</p>
+<p>To use the menu in your activity, you need to inflate the menu resource (convert the XML
+resource into a programmable object) using {@link android.view.MenuInflater#inflate(int,Menu)
+MenuInflater.inflate()}. In the following sections, you'll see how to inflate a menu for each
+menu type.</p>
 
 
 
-<h2 id="features">Other Menu Features</h2>
+<h2 id="options-menu">Creating an Options Menu</h2>
 
-<p>Here are some other features that you can apply to most menu items.</p>
+<div class="figure" style="width:200px;margin:0">
+  <img src="{@docRoot}images/options_menu.png" height="333" alt="" />
+  <p class="img-caption"><strong>Figure 1.</strong> Options menu in the
+Browser, on Android 2.3.</p>
+</div>
 
-<h3 id="groups">Menu groups</h3>
+<p>The options menu is where you should include actions and other options that are relevant to the
+current activity context, such as "Search," "Compose email," and "Settings."</p>
+
+<p>Where the items in your options menu appear on the screen depends on the version for which you've
+developed your application:</p>
+
+<ul>
+  <li>If you've developed your application for <strong>Android 2.3.x (API level 10) or
+lower</strong>, the contents of your options menu appear at the bottom of the screen when the user
+presses the <em>Menu</em> button, as shown in figure 1. When opened, the first visible portion is
+the icon
+menu, which holds up to six menu items. If your menu includes more than six items, Android places
+the sixth item and the rest into the overflow menu, which the user can open by selecting
+<em>More</em>.</li>
+
+  <li>If you've developed your application for <strong>Android 3.0 (API level 11) and
+higher</strong>, items from the options menu are available in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>. By default, the system
+places all items in the action overflow, which the user can reveal with the action overflow icon on
+the right side of the action bar (or by pressing the device <em>Menu</em> button, if available). To
+enable
+quick access to important actions, you can promote a few items to appear in the action bar by adding
+{@code android:showAsAction="ifRoom"} to the corresponding {@code &lt;item&gt;} elements (see figure
+2). <p>For more information about action items and other action bar behaviors, see the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> guide. </p>
+<p class="note"><strong>Note:</strong> Even if you're <em>not</em> developing for Android 3.0 or
+higher, you can build your own action bar layout for a similar effect. For an example of how you can
+support older versions of Android with an action bar, see the <a
+href="{@docRoot}resources/samples/ActionBarCompat/index.html">Action Bar Compatibility</a>
+sample.</p>
+</li>
+</ul>
+
+<img src="{@docRoot}images/ui/actionbar.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> Action bar from the <a
+href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> app, showing
+navigation tabs and a camera action item (plus the action overflow button).</p>
+
+<p>You can declare items for the options menu from either your {@link android.app.Activity}
+subclass or a {@link android.app.Fragment} subclass. If both your activity and fragment(s)
+declare items for the options menu, they are combined in the UI. The activity's items appear
+first, followed by those of each fragment in the order in which each fragment is added to the
+activity. If necessary, you can re-order the menu items with the {@code android:orderInCategory}
+attribute in each {@code &lt;item&gt;} you need to move.</p>
+
+<p>To specify the options menu for an activity, override {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} (fragments provide their
+own {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} callback). In this
+method, you can inflate your menu resource (<a href="#xml">defined in XML</a>) into the {@link
+android.view.Menu} provided in the callback. For example:</p>
+
+<pre>
+&#64;Override
+public boolean onCreateOptionsMenu(Menu menu) {
+    MenuInflater inflater = {@link android.app.Activity#getMenuInflater()};
+    inflater.inflate(R.menu.game_menu, menu);
+    return true;
+}
+</pre>
+
+<p>You can also add menu items using {@link android.view.Menu#add(int,int,int,int)
+add()} and retrieve items with {@link android.view.Menu#findItem findItem()} to revise their
+properties with {@link android.view.MenuItem} APIs.</p>
+
+<p>If you've developed your application for Android 2.3.x and lower, the system calls {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} to create the options menu
+when the user opens the menu for the first time. If you've developed for Android 3.0 and higher, the
+system calls {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} when
+starting the activity, in order to show items to the action bar.</p>
+
+
+
+<h3 id="RespondingOptionsMenu">Handling click events</h3>
+
+<p>When the user selects an item from the options menu (including action items in the action bar),
+the system calls your activity's {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} method. This method passes the {@link android.view.MenuItem} selected. You
+can identify the item by calling {@link android.view.MenuItem#getItemId()}, which returns the unique
+ID for the menu item (defined by the {@code android:id} attribute in the menu resource or with an
+integer given to the {@link android.view.Menu#add(int,int,int,int) add()} method). You can match
+this ID against known menu items to perform the appropriate action. For example:</p>
+
+<pre>
+&#64;Override
+public boolean onOptionsItemSelected(MenuItem item) {
+    // Handle item selection
+    switch (item.getItemId()) {
+        case R.id.new_game:
+            newGame();
+            return true;
+        case R.id.help:
+            showHelp();
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+    }
+}
+</pre>
+
+<p>When you successfully handle a menu item, return {@code true}. If you don't handle the menu
+item, you should call the superclass implementation of {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} (the default
+implementation returns false).</p>
+
+<p>If your activity includes fragments, the system first calls {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} for the activity then
+for each fragment (in the order each fragment was added) until one returns
+{@code true} or all fragments have been called.</p>
+
+<p class="note"><strong>Tip:</strong> Android 3.0 adds the ability for you to define the on-click
+behavior for a menu item in XML, using the {@code android:onClick} attribute. The value for the
+attribute must be the name of a method defined by the activity using the menu. The method
+must be public and accept a single {@link android.view.MenuItem} parameter&mdash;when the system
+calls this method, it passes the menu item selected. For more information and an example, see the <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> document.</p>
+
+<p class="note"><strong>Tip:</strong> If your application contains multiple activities and
+some of them provide the same options menu, consider creating
+an activity that implements nothing except the {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} and {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} methods. Then extend this class for each activity that should share the
+same options menu. This way, you can manage one set of code for handling menu
+actions and each descendant class inherits the menu behaviors.
+If you want to add menu items to one of the descendant activities,
+override {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} in that activity. Call {@code super.onCreateOptionsMenu(menu)} so the
+original menu items are created, then add new menu items with {@link
+android.view.Menu#add(int,int,int,int) menu.add()}. You can also override the super class's
+behavior for individual menu items.</p>
+
+
+<h3 id="ChangingTheMenu">Changing menu items at runtime</h3>
+
+<p>After the system calls {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()}, it retains an instance of the {@link android.view.Menu} you populate and
+will not call {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}
+again unless the menu is invalidated for some reason. However, you should use {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} only to create the initial
+menu state and not to make changes during the activity lifecycle.</p>
+
+<p>If you want to modify the options menu based on 
+events that occur during the activity lifecycle, you can do so in
+the {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} method. This
+method passes you the {@link android.view.Menu} object as it currently exists so you can modify it,
+such as add, remove, or disable items. (Fragments also provide an {@link
+android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()} callback.)</p>
+
+<p>On Android 2.3.x and lower, the system calls {@link
+android.app.Activity#onPrepareOptionsMenu(Menu)
+onPrepareOptionsMenu()} each time the user opens the options menu (presses the <em>Menu</em>
+button).</p>
+
+<p>On Android 3.0 and higher, the options menu is considered to always be open when menu items are
+presented in the action bar. When an event occurs and you want to perform a menu update, you must
+call {@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} to request that the
+system call {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}.</p>
+
+<p class="note"><strong>Note:</strong> 
+You should never change items in the options menu based on the {@link android.view.View} currently
+in focus. When in touch mode (when the user is not using a trackball or d-pad), views
+cannot take focus, so you should never use focus as the basis for modifying
+items in the options menu. If you want to provide menu items that are context-sensitive to a {@link
+android.view.View}, use a <a href="#context-menu">Context Menu</a>.</p>
+
+
+
+
+<h2 id="context-menu">Creating Contextual Menus</h2>
+
+<div class="figure" style="width:420px;margin-top:-1em">
+  <img src="{@docRoot}images/ui/menu-context.png" alt="" />
+  <p class="img-caption"><strong>Figure 3.</strong> Screenshots of a floating context menu (left)
+and the contextual action bar (right).</p>
+</div>
+
+<p>A contextual menu offers actions that affect a specific item or context frame in the UI. You
+can provide a context menu for any view, but they are most often used for items in a {@link
+android.widget.ListView}, {@link android.widget.GridView}, or other view collections in which
+the user can perform direct actions on each item.</p>
+
+<p>There are two ways to provide contextual actions:</p>
+<ul>
+  <li>In a <a href="#FloatingContextMenu">floating context menu</a>. A menu appears as a
+floating list of menu items (similar to a dialog) when the user performs a long-click (press and
+hold) on a view that declares support for a context menu. Users can perform a contextual
+action on one item at a time.</li>
+
+  <li>In the <a href="#CAB">contextual action mode</a>. This mode is a system implementation of
+{@link android.view.ActionMode} that displays a <em>contextual action bar</em> at the top of the
+screen with action items that affect the selected item(s). When this mode is active, users
+can perform an action on multiple items at once (if your app allows it).</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> The contextual action mode is available on Android 3.0 (API
+level 11) and higher and is the preferred technique for displaying contextual actions when
+available. If your app supports versions lower than 3.0 then you should fall back to a floating
+context menu on those devices.</p>
+
+
+<h3 id="FloatingContextMenu">Creating a floating context menu</h3>
+
+<p>To provide a floating context menu:</p>
+<ol>
+  <li>Register the {@link android.view.View} to which the context menu should be associated by
+calling {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} and pass
+it the {@link android.view.View}.
+  <p>If your activity uses a {@link android.widget.ListView} or {@link android.widget.GridView} and
+you want each item to provide the same context menu, register all items for a context menu by
+passing the {@link android.widget.ListView} or {@link android.widget.GridView} to {@link
+android.app.Activity#registerForContextMenu(View) registerForContextMenu()}.</p>
+</li>
+
+  <li>Implement the {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} method
+in your {@link android.app.Activity} or {@link android.app.Fragment}.
+  <p>When the registered view receives a long-click event, the system calls your {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
+method. This is where you define the menu items, usually by inflating a menu resource. For
+example:</p>
+<pre>
+&#64;Override
+public void onCreateContextMenu(ContextMenu menu, View v,
+                                ContextMenuInfo menuInfo) {
+    super.onCreateContextMenu(menu, v, menuInfo);
+    MenuInflater inflater = getMenuInflater();
+    inflater.inflate(R.menu.context_menu, menu);
+}
+</pre>
+
+<p>{@link android.view.MenuInflater} allows you to inflate the context menu from a <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. The callback method
+parameters include the {@link android.view.View}
+that the user selected and a {@link android.view.ContextMenu.ContextMenuInfo} object that provides
+additional information about the item selected. If your activity has several views that each provide
+a different context menu, you might use these parameters to determine which context menu to
+inflate.</p>
+</li>
+
+<li>Implement {@link android.app.Activity#onContextItemSelected(MenuItem)
+onContextItemSelected()}.
+  <p>When the user selects a menu item, the system calls this method so you can perform the
+appropriate action. For example:</p>
+
+<pre>
+&#64;Override
+public boolean onContextItemSelected(MenuItem item) {
+    AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+    switch (item.getItemId()) {
+        case R.id.edit:
+            editNote(info.id);
+            return true;
+        case R.id.delete:
+            deleteNote(info.id);
+            return true;
+        default:
+            return super.onContextItemSelected(item);
+    }
+}
+</pre>
+
+<p>The {@link android.view.MenuItem#getItemId()} method queries the ID for
+the selected menu item, which you should assign to each menu item in XML using the {@code
+android:id} attribute, as shown in the section about <a href="#xml">Defining a Menu in
+XML</a>.</p>
+
+<p>When you successfully handle a menu item, return {@code true}. If you don't handle the menu item,
+you should pass the menu item to the superclass implementation. If your activity includes fragments,
+the activity receives this callback first. By calling the superclass when unhandled, the system
+passes the event to the respective callback method in each fragment, one at a time (in the order
+each fragment was added) until {@code true} or {@code false} is returned. (The default
+implementation for {@link android.app.Activity} and {@code android.app.Fragment} return {@code
+false}, so you should always call the superclass when unhandled.)</p>
+</li>
+</ol>
+
+
+<h3 id="CAB">Using the contextual action mode</h3>
+
+<p>The contextual action mode is a system implementation of {@link android.view.ActionMode} that
+focuses user interaction toward performing contextual actions. When a
+user enables this mode by selecting an item, a <em>contextual action bar</em> appears at the top of
+the screen to present actions the user can perform on the currently selected item(s). While this
+mode is enabled, the user can select multiple items (if you allow it), deselect items, and continue
+to navigate within the activity (as much as you're willing to allow). The action mode is disabled
+and the contextual action bar disappears when the user deselects all items, presses the BACK button,
+or selects the <em>Done</em> action on the left side of the bar.</p>
+
+<p class="note"><strong>Note:</strong> The contextual action bar is not necessarily
+associated with the <a href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>. They operate
+independently, even though the contextual action bar visually overtakes the action bar
+position.</p>
+
+<p>If you're developing for Android 3.0 (API level 11) or higher, you
+should usually use the contextual action mode to present contextual actions, instead of the <a
+href="#FloatingContextMenu">floating context menu</a>.</p>
+
+<p>For views that provide contextual actions, you should usually invoke the contextual action mode
+upon one of two events (or both):</p>
+<ul>
+  <li>The user performs a long-click on the view.</li>
+  <li>The user selects a checkbox or similar UI component within the view.</li>
+</ul>
+
+<p>How your application invokes the contextual action mode and defines the behavior for each
+action depends on your design. There are basically two designs:</p>
+<ul>
+  <li>For contextual actions on individual, arbitrary views.</li>
+  <li>For batch contextual actions on groups of items in a {@link
+android.widget.ListView} or {@link android.widget.GridView} (allowing the user to select multiple
+items and perform an action on them all).</li>
+</ul>
+
+<p>The following sections describe the setup required for each scenario.</p>
+
+
+<h4 id="CABforViews">Enabling the contextual action mode for individual views</h4>
+
+<p>If you want to invoke the contextual action mode only when the user selects specific
+views, you should:</p>
+<ol>
+  <li>Implement the {@link android.view.ActionMode.Callback} interface. In its callback methods, you
+can specify the actions for the contextual action bar, respond to click events on action items, and
+handle other lifecycle events for the action mode.</li>
+  <li>Call {@link android.app.Activity#startActionMode startActionMode()} when you want to show the
+bar (such as when the user long-clicks the view).</li>
+</ol>
+
+<p>For example:</p>
+
+<ol>
+  <li>Implement the {@link android.view.ActionMode.Callback ActionMode.Callback} interface:
+<pre>
+private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
+
+    // Called when the action mode is created; startActionMode() was called
+    &#64;Override
+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        // Inflate a menu resource providing context menu items
+        MenuInflater inflater = mode.getMenuInflater();
+        inflater.inflate(R.menu.context_menu, menu);
+        return true;
+    }
+
+    // Called each time the action mode is shown. Always called after onCreateActionMode, but
+    // may be called multiple times if the mode is invalidated.
+    &#64;Override
+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+        return false; // Return false if nothing is done
+    }
+
+    // Called when the user selects a contextual menu item
+    &#64;Override
+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.menu_share:
+                shareCurrentItem();
+                mode.finish(); // Action picked, so close the CAB
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    // Called when the user exits the action mode
+    &#64;Override
+    public void onDestroyActionMode(ActionMode mode) {
+        mActionMode = null;
+    }
+};
+</pre>
+
+<p>Notice that these event callbacks are almost exactly the same as the callbacks for the <a
+href="#options-menu">options menu</a>, except each of these also pass the {@link
+android.view.ActionMode} object associated with the event. You can use {@link
+android.view.ActionMode} APIs to make various changes to the CAB, such as revise the title and
+subtitle with {@link android.view.ActionMode#setTitle setTitle()} and {@link
+android.view.ActionMode#setSubtitle setSubtitle()} (useful to indicate how many items are
+selected).</p>
+
+<p>Also notice that the above sample sets the {@code mActionMode} variable null when the
+action mode is destroyed. In the next step, you'll see how it's initialized and how saving
+the member variable in your activity or fragment can be useful.</p>
+</li>
+
+  <li>Call {@link android.app.Activity#startActionMode startActionMode()} to enable the contextual
+action mode when appropriate, such as in response to a long-click on a {@link
+android.view.View}:</p>
+
+<pre>
+someView.setOnLongClickListener(new View.OnLongClickListener() {
+    // Called when the user long-clicks on someView
+    public boolean onLongClick(View view) {
+        if (mActionMode != null) {
+            return false;
+        }
+
+        // Start the CAB using the ActionMode.Callback defined above
+        mActionMode = getActivity().startActionMode(mActionModeCallback);
+        view.setSelected(true);
+        return true;
+    }
+});
+</pre>
+
+<p>When you call {@link android.app.Activity#startActionMode startActionMode()}, the system returns
+the {@link android.view.ActionMode} created. By saving this in a member variable, you can
+make changes to the contextual action bar in response to other events. In the above sample, the
+{@link android.view.ActionMode} is used to ensure that the {@link android.view.ActionMode} instance
+is not recreated if it's already active, by checking whether the member is null before starting the
+action mode.</p>
+</li>
+</ol>
+
+
+
+<h4 id="CABforListView">Enabling batch contextual actions in a ListView or GridView</h4>
+
+<p>If you have a collection of items in a {@link android.widget.ListView} or {@link
+android.widget.GridView} (or another extension of {@link android.widget.AbsListView}) and want to
+allow users to perform batch actions, you should:</p>
+
+<ul>
+  <li>Implement the {@link android.widget.AbsListView.MultiChoiceModeListener} interface and set it
+for the view group with {@link android.widget.AbsListView#setMultiChoiceModeListener
+setMultiChoiceModeListener()}. In the listener's callback methods, you can specify the actions
+for the contextual action bar, respond to click events on action items, and handle other callbacks
+inherited from the {@link android.view.ActionMode.Callback} interface.</li>
+
+  <li>Call {@link android.widget.AbsListView#setChoiceMode setChoiceMode()} with the {@link
+android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL} argument.</li>
+</ul>
+
+<p>For example:</p>
+
+<pre>
+ListView listView = getListView();
+listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
+
+    &#64;Override
+    public void onItemCheckedStateChanged(ActionMode mode, int position,
+                                          long id, boolean checked) {
+        // Here you can do something when items are selected/de-selected,
+        // such as update the title in the CAB
+    }
+
+    &#64;Override
+    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+        // Respond to clicks on the actions in the CAB
+        switch (item.getItemId()) {
+            case R.id.menu_delete:
+                deleteSelectedItems();
+                mode.finish(); // Action picked, so close the CAB
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    &#64;Override
+    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        // Inflate the menu for the CAB
+        MenuInflater inflater = mode.getMenuInflater();
+        inflater.inflate(R.menu.context, menu);
+        return true;
+    }
+
+    &#64;Override
+    public void onDestroyActionMode(ActionMode mode) {
+        // Here you can make any necessary updates to the activity when
+        // the CAB is removed. By default, selected items are deselected/unchecked.
+    }
+
+    &#64;Override
+    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+        // Here you can perform updates to the CAB due to
+        // an {@link android.view.ActionMode#invalidate} request
+        return false;
+    }
+});
+</pre>
+
+<p>That's it. Now when the user selects an item with a long-click, the system calls the {@link
+android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()}
+method and displays the contextual action bar with the specified actions. While the contextual
+action bar is visible, users can select additional items.</p>
+
+<p>In some cases in which the contextual actions provide common action items, you might
+want to add a checkbox or a similar UI element that allows users to select items, because they
+might not discover the long-click behavior. When a user selects the checkbox, you
+can invoke the contextual action mode by setting the respective list item to the checked
+state with {@link android.widget.AbsListView#setItemChecked setItemChecked()}.</p>
+
+
+
+
+<h2 id="PopupMenu">Creating a Popup Menu</h2>
+
+<div class="figure" style="width:220px">
+<img src="{@docRoot}images/ui/popupmenu.png" alt="" />
+<p><strong>Figure 4.</strong> A popup menu in the Gmail app, anchored to the overflow
+button at the top-right.</p>
+</div>
+
+<p>A {@link android.widget.PopupMenu} is a modal menu anchored to a {@link android.view.View}.
+It appears below the anchor view if there is room, or above the view otherwise. It's useful for:</p>
+<ul>
+  <li>Providing an overflow-style menu for actions that <em>relate to</em> specific content (such as
+Gmail's email headers, shown in figure 4).
+    <p class="note"><strong>Note:</strong> This is not the same as a context menu, which is
+generally for actions that <em>affect</em> selected content. For actions that affect selected
+content, use the <a href="#CAB">contextual action mode</a> or <a
+href="#FloatingContextMenu">floating context menu</a>.</p></li>
+  <li>Providing a second part of a command sentence (such as a button marked "Add"
+that produces a popup menu with different "Add" options).</li>
+  <li>Providing a drop-down similar to {@link android.widget.Spinner} that does not retain
+a persistent selection.</li>
+</ul>
+
+
+<p class="note"><strong>Note:</strong> {@link android.widget.PopupMenu} is available with API
+level 11 and higher.</p>
+
+<p>If you <a href="#xml">define your menu in XML</a>, here's how you can show the popup menu:</p>
+<ol>
+  <li>Instantate a {@link android.widget.PopupMenu} with its constructor, which takes the
+current application {@link android.content.Context} and the {@link android.view.View} to which the
+menu should be anchored.</li>
+  <li>Use {@link android.view.MenuInflater} to inflate your menu resource into the {@link
+android.view.Menu} object returned by {@link
+android.widget.PopupMenu#getMenu() PopupMenu.getMenu()}. On API level 14 and above, you can use
+{@link android.widget.PopupMenu#inflate PopupMenu.inflate()} instead.</li>
+  <li>Call {@link android.widget.PopupMenu#show() PopupMenu.show()}.</li>
+</ol>
+
+<p>For example, here's a button with the {@link android.R.attr#onClick android:onClick} attribute
+that shows a popup menu:</p>
+
+<pre>
+&lt;ImageButton
+    android:layout_width="wrap_content" 
+    android:layout_height="wrap_content" 
+    android:src="@drawable/ic_overflow_holo_dark"
+    android:contentDescription="@string/descr_overflow_button"
+    android:onClick="showPopup" />
+</pre>
+
+<p>The activity can then show the popup menu like this:</p>
+
+<pre>
+public void showPopup(View v) {
+    PopupMenu popup = new PopupMenu(this, v);
+    MenuInflater inflater = popup.getMenuInflater();
+    inflater.inflate(R.menu.actions, popup.getMenu());
+    popup.show();
+}
+</pre>
+
+<p>In API level 14 and higher, you can combine the two lines that inflate the menu with {@link
+android.widget.PopupMenu#inflate PopupMenu.inflate()}.</p>
+
+<p>The menu is dismissed when the user selects an item or touches outside the menu
+area. You can listen for the dismiss event using {@link
+android.widget.PopupMenu.OnDismissListener}.</p>
+
+<h3 id="PopupEvents">Handling click events</h3>
+
+<p>To perform an
+action when the user selects a menu item, you must implement the {@link
+android.widget.PopupMenu.OnMenuItemClickListener} interface and register it with your {@link
+android.widget.PopupMenu} by calling {@link android.widget.PopupMenu#setOnMenuItemClickListener
+setOnMenuItemclickListener()}. When the user selects an item, the system calls the {@link
+android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} callback in
+your interface.</p>
+
+<p>For example:</p>
+
+<pre>
+public void showMenu(View v) {
+    PopupMenu popup = new PopupMenu(this, v);
+
+    // This activity implements OnMenuItemClickListener
+    popup.setOnMenuItemClickListener(this);
+    popup.inflate(R.menu.actions);
+    popup.show();
+}
+
+&#64;Override
+public boolean onMenuItemClick(MenuItem item) {
+    switch (item.getItemId()) {
+        case R.id.archive:
+            archive(item);
+            return true;
+        case R.id.delete:
+            delete(item);
+            return true;
+        default:
+            return false;
+    }
+}
+</pre>
+
+
+<h2 id="groups">Creating Menu Groups</h2>
 
 <p>A menu group is a collection of menu items that share certain traits. With a group, you
 can:</p>
@@ -473,38 +842,41 @@
 <pre>
 &lt;?xml version="1.0" encoding="utf-8"?&gt;
 &lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
-    &lt;item android:id="@+id/item1"
-          android:icon="@drawable/item1"
-          android:title="@string/item1" /&gt;
+    &lt;item android:id="@+id/menu_save"
+          android:icon="@drawable/menu_save"
+          android:title="@string/menu_save" /&gt;
     &lt;!-- menu group --&gt;
-    &lt;group android:id="@+id/group1"&gt;
-        &lt;item android:id="@+id/groupItem1"
-              android:title="@string/groupItem1" /&gt;
-        &lt;item android:id="@+id/groupItem2"
-              android:title="@string/groupItem2" /&gt;
+    &lt;group android:id="@+id/group_delete"&gt;
+        &lt;item android:id="@+id/menu_archive"
+              android:title="@string/menu_archive" /&gt;
+        &lt;item android:id="@+id/menu_delete"
+              android:title="@string/menu_delete" /&gt;
     &lt;/group&gt;
 &lt;/menu&gt;
 </pre>
 
-<p>The items that are in the group appear the same as the first item that is not in a
-group&mdash;all three items in the menu are siblings. However, you can modify the traits of the two
-items in the group by referencing the group ID and using the methods listed above.</p>
+<p>The items that are in the group appear at the same level as the first item&mdash;all three items
+in the menu are siblings. However, you can modify the traits of the two
+items in the group by referencing the group ID and using the methods listed above. The system
+will also never separate grouped items. For example, if you declare {@code
+android:showAsAction="ifRoom"} for each item, they will either both appear in the action
+bar or both appear in the action overflow.</p>
 
 
-<h3 id="checkable">Checkable menu items</h3>
+<h3 id="checkable">Using checkable menu items</h3>
 
 <div class="figure" style="width:200px">
   <img src="{@docRoot}images/radio_buttons.png" height="333" alt="" />
-  <p class="img-caption"><strong>Figure 3.</strong> Screenshot of a submenu with checkable
+  <p class="img-caption"><strong>Figure 5.</strong> Screenshot of a submenu with checkable
 items.</p>
 </div>
 
 <p>A menu can be useful as an interface for turning options on and off, using a checkbox for
 stand-alone options, or radio buttons for groups of
-mutually exclusive options. Figure 2 shows a submenu with items that are checkable with radio
+mutually exclusive options. Figure 5 shows a submenu with items that are checkable with radio
 buttons.</p>
 
-<p class="note"><strong>Note:</strong> Menu items in the Icon Menu (from the Options Menu) cannot
+<p class="note"><strong>Note:</strong> Menu items in the Icon Menu (from the options menu) cannot
 display a checkbox or radio button. If you choose to make items in the Icon Menu checkable,
 you must manually indicate the checked state by swapping the icon and/or text
 each time the state changes.</p>
@@ -550,15 +922,15 @@
 <pre>
 &#64;Override
 public boolean onOptionsItemSelected(MenuItem item) {
-  switch (item.getItemId()) {
-  case R.id.vibrate:
-  case R.id.dont_vibrate:
-    if (item.isChecked()) item.setChecked(false);
-    else item.setChecked(true);
-    return true;
-  default:
-    return super.onOptionsItemSelected(item);
-  }
+    switch (item.getItemId()) {
+        case R.id.vibrate:
+        case R.id.dont_vibrate:
+            if (item.isChecked()) item.setChecked(false);
+            else item.setChecked(true);
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+    }
 }
 </pre>
 
@@ -575,30 +947,8 @@
 href="{@docRoot}guide/topics/data/data-storage.html#pref">Shared Preferences</a>.</p>
 
 
-<h3 id="shortcuts">Shortcut keys</h3>
 
-<p>To facilitate quick access to items in the Options Menu when the user's device has a hardware
-keyboard, you can add quick-access shortcut keys using letters and/or numbers, with the
-{@code android:alphabeticShortcut} and {@code android:numericShortcut} attributes in the {@code
-&lt;item&gt;} element. You can also use the methods {@link
-android.view.MenuItem#setAlphabeticShortcut(char)} and {@link
-android.view.MenuItem#setNumericShortcut(char)}. Shortcut keys are <em>not</em>
-case sensitive.</p>
-
-<p>For example, if you apply the "s" character as an alphabetic shortcut to a "save" menu item, then
-when the menu is open (or while the user holds the MENU button) and the user presses the "s" key,
-the "save" menu item is selected.</p>
-
-<p>This shortcut key is displayed as a tip in the menu item, below the menu item name
-(except for items in the Icon Menu, which are displayed only if the user holds the MENU
-button).</p>
-
-<p class="note"><strong>Note:</strong> Shortcut keys for menu items only work on devices with a
-hardware keyboard. Shortcuts cannot be added to items in a Context Menu.</p>
-
-
-
-<h3 id="intents">Dynamically adding menu intents</h3>
+<h2 id="intents">Adding Menu Items Based on an Intent</h2>
 
 <p>Sometimes you'll want a menu item to launch an activity using an {@link android.content.Intent}
 (whether it's an activity in your application or another application). When you know the intent you
@@ -671,7 +1021,7 @@
 argument.</p>
 
 
-<h4>Allowing your activity to be added to other menus</h4>
+<h3 id="AllowingToAdd">Allowing your activity to be added to other menus</h3>
 
 <p>You can also offer the services of your activity to other applications, so your
 application can be included in the menu of others (reverse the roles described above).</p>
@@ -681,7 +1031,7 @@
 and/or {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} values for the intent filter
 category. For example:</p>
 <pre>
-&lt;intent-filter label="Resize Image">
+&lt;intent-filter label="&#64;string/resize_image">
     ...
     &lt;category android:name="android.intent.category.ALTERNATIVE" />
     &lt;category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 33b0fec..d104b4b 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -173,7 +173,7 @@
   </li>
   <li>
     The user has seen enough to know they have a meeting coming up,
-    so they press the BACK button.  They are now returned to Email, which
+    so they press the <em>Back</em> button.  They are now returned to Email, which
     is where they were when they took the notification.
   </li>
 </ol>
@@ -198,8 +198,8 @@
     (writing an e-mail), but that message is still saved in their drafts.
   </li>
   <li>
-    The user presses BACK once to go to the message list (the typical flow in the
-    Email app), and press BACK again to return to Calendar as they left it.
+    The user presses <em>Back</em> once to go to the message list (the typical flow in the
+    Email app), and press <em>Back</em> again to return to Calendar as they left it.
   </li>
 </ol>
 
@@ -216,7 +216,7 @@
 most interest is the <code>makeMessageIntentStack()</code> method, which constructs
 an array of intents representing the app's new activity stack for this state.
 (If you are using fragments, you may need to initialize your fragment and
-app state so that pressing BACK will switch the UI back to its parent state.)
+app state so that pressing <em>Back</em> will switch the UI back to its parent state.)
 The core of this is the {@link android.content.Intent#makeRestartActivityTask
 Intent.makeRestartActivityTask()} method, which constructs the root activity
 of the stack with the appropriate flags, such as
@@ -245,31 +245,27 @@
 activity like this can cause it to be mixed with your normal application back stack
 in undesired ways.  To make it behave correctly, in the manifest declaration
 for the activity the attributes 
-<code>android:launchMode="singleInstance"</code> and
+<code>android:launchMode="singleTask"</code>,
+<code>android:taskAffinity=""</code> and
 <code>android:excludeFromRecents="true"</code>
 must be set.  The full activity declaration for this sample is:</p>
 
 {@sample development/samples/ApiDemos/AndroidManifest.xml interstitial_affinity}
 
-<p>Because of the use of <code>singleInstance</code>, you must be careful about launching
-any other activities from this one.  These activities will be launched
-in their own task, and care must be taken to make sure this interacts
-well with the current state of your application's task.  This is essentially
+<p>You must be careful when launching other activities from this initial activity,
+because this is not a top-level part of the application, does not appear in
+recents, and needs to be relaunched at any point from the notification with new data
+to show.  This best approach is to make sure any activity launched from it is
+launched in its own task.  When doing this care must be taken to make sure this
+new task interacts well with the current state of your exiting application's
+task.  This is essentially
 the same as switching to the main application as described for the Email style
 notification shown before.  Given the <code>makeMessageIntentStack()</code>
-method previously shown, handling a click here would look something like this:</p>
+method previously shown, handling a click then would look something like this:</p>
 
 {@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageInterstitial.java
   app_launch}
 
-<p>If you don't want to use the <code>singleInstance</code> launch mode for
-this activity, an alternative approach is to use <code>android:taskAffinity=""</code>.
-This tells Android that the activity should not be treated as part of the
-main application flow, so it will not get mixed together with that.  All of the
-other issues discussed here do still apply, though this would allow you to start
-additional activities that are part of this notification task instead of switching
-to and replacing the main application task.</p>
-
 <h2 id="ManageYourNotifications">Managing your Notifications</h2>
 
 <p>The {@link android.app.NotificationManager} is a system service that manages all
diff --git a/docs/html/guide/webapps/webview.jd b/docs/html/guide/webapps/webview.jd
index ed28f21..66b5501 100644
--- a/docs/html/guide/webapps/webview.jd
+++ b/docs/html/guide/webapps/webview.jd
@@ -298,18 +298,18 @@
 pages. You can navigate backward and forward through the history with {@link
 android.webkit.WebView#goBack()} and {@link android.webkit.WebView#goForward()}.</p>
 
-<p>For example, here's how your {@link android.app.Activity} can use the device BACK key to navigate
-backward:</p>
+<p>For example, here's how your {@link android.app.Activity} can use the device <em>Back</em> button
+to navigate backward:</p>
 
 <pre>
 &#64;Override
 public boolean {@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown}(int keyCode, KeyEvent event) {
-    // Check if the key event was the BACK key and if there's history
+    // Check if the key event was the Back button and if there's history
     if ((keyCode == KeyEvent.KEYCODE_BACK) &amp;&amp; myWebView.{@link android.webkit.WebView#canGoBack() canGoBack}() {
         myWebView.{@link android.webkit.WebView#goBack() goBack}();
         return true;
     }
-    // If it wasn't the BACK key or there's no web page history, bubble up to the default
+    // If it wasn't the Back key or there's no web page history, bubble up to the default
     // system behavior (probably exit the activity)
     return super.onKeyDown(keyCode, event);
 }
diff --git a/docs/html/images/ui/menu-context.png b/docs/html/images/ui/menu-context.png
new file mode 100644
index 0000000..f6975fb
--- /dev/null
+++ b/docs/html/images/ui/menu-context.png
Binary files differ
diff --git a/docs/html/images/ui/popupmenu.png b/docs/html/images/ui/popupmenu.png
new file mode 100644
index 0000000..5c99821
--- /dev/null
+++ b/docs/html/images/ui/popupmenu.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 9197b5d..b9d6758 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,4 +1,5 @@
 home=true
+page.metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
 @jd:body
 
 
@@ -142,6 +143,20 @@
 + "href='{@docRoot}sdk/api_diff/15/changes.html'>diff report</a>. If you're new to Android, "
 + "get started with the <a href='/sdk/index.html'>SDK starter package</a>.</p>"
     },
+    
+    'plus': {
+      'layout':"imgLeft",
+      'icon':"google-plus-small.png",
+      'name':"Google+ Page",
+      'img':"google-plus.png",
+      'title':"Android Developers on Google+",
+      'desc': "<p>We now have a Google+ page for <a "
++ "href='https://plus.google.com/108967384991768947849'>+Android Developers</a>. "
++ "We'll use it to host Hangouts for developers, talk about the latest releases, "
++ "development and design tips, and much more.</p>"
++ "<div style='margin:.7em 0 0 -1.2em'><g:plus href='https://plus.google.com/108967384991768947849' "
++ "size=\"smallbadge\" width=\"275\"></g:plus></div>"
+    },
 
     'tv': {
       'layout':"imgLeft",
@@ -186,5 +201,16 @@
 </script>
 <script type="text/javascript" src="{@docRoot}assets/carousel.js"></script>
 <script type="text/javascript">
-  initCarousel("sdk");
+  initCarousel("plus");
 </script>
+
+<script type="text/javascript" src="https://plus.google.com/108967384991768947849"
+rel="publisher"></script>
+<script type="text/javascript">
+window.___gcfg = {lang: 'en'};
+(function() 
+{var po = document.createElement("script");
+po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
+var s = document.getElementsByTagName("script")[0];
+s.parentNode.insertBefore(po, s);
+})();</script>
diff --git a/docs/html/resources/articles/faster-screen-orientation-change.jd b/docs/html/resources/articles/faster-screen-orientation-change.jd
index 52531bb..e7b73bf 100644
--- a/docs/html/resources/articles/faster-screen-orientation-change.jd
+++ b/docs/html/resources/articles/faster-screen-orientation-change.jd
@@ -58,7 +58,7 @@
 
 <p>When your application displays a lot of data, or data that is expensive to fetch,
 the automatic destruction/creation of the activities can be lead to a
-painful user experience. Take the example of <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/">Photostream</a>,
+painful user experience. Take the example of <a href="http://code.google.com/p/apps-for-android/source/browse/#git%2FPhotostream%2Fsrc%2Fcom%2Fgoogle%2Fandroid%2Fphotostream">Photostream</a>,
 a simple Flickr browsing application. After you launch the application and choose a Flickr account, the
 application downloads a set of 6 photos (on a T-Mobile G1) from the
 Flickr servers and displays them on screen. To improve the user
@@ -80,9 +80,9 @@
 
 <p>The Activity class has a special method called 
 {@link android.app.Activity#onRetainNonConfigurationInstance()}. This method 
-can be used to pass an arbitrary object <em>your future self</em> and Android 
+can be used to pass an arbitrary object to <em>your future self</em> and Android 
 is smart enough to call this method only when needed. In the case of Photostream, 
-the application <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java#226">used this method</a>
+the application used this method
 to pass the downloaded images to the future activity on orientation change. 
 The implementation can be summarized like so:</p>
 
@@ -96,7 +96,7 @@
 
 <p>In the new activity, in <code>onCreate()</code>, all you have to do to 
 get your object back is to call {@link android.app.Activity#getLastNonConfigurationInstance()}. 
-In Photostream, <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java#251">this method is invoked</a> 
+In Photostream, this method is invoked 
 and if the returned value is not null, the grid is loaded with the list of 
 photos from the previous activity:</p>
 
@@ -128,3 +128,6 @@
 <code>onRetainNonConfigurationChange()</code> should be used only to retain 
 data that is expensive to load. Otherwise, keep it simple and let Android 
 do everything.</p>
+
+<p>Also read the guide to <a href="{@docRoot}guide/topics/resources/runtime-changes.html">Handling Runtime
+Changes</a>.</p>
diff --git a/docs/html/resources/community-more.jd b/docs/html/resources/community-more.jd
index df72926..3089d45 100644
--- a/docs/html/resources/community-more.jd
+++ b/docs/html/resources/community-more.jd
@@ -1,5 +1,5 @@
 community=true
-page.title=IRC and Twitter
+page.title=IRC, G+, Twitter
 @jd:body
 
 <p>In addition to the <a href="community-groups.html">Android developer forums</a>, you can participate in the Android developer community through IRC and you can follow us on Twitter. </p>
@@ -45,8 +45,27 @@
 </li>
 </ul>
 
+
+<h3 id="gplus">Google+</h3>
+<p>We use a Google+ page to host Hangouts for developers, talk about the latest
+releases, development and design tips, and much more.</p>
+
+<div style='margin-top:1em'><g:plus href='https://plus.google.com/108967384991768947849'
+size='badge'></g:plus></div>
+
+
 <h3 id="twitter">Twitter</h3>
 <p>You can follow us on Twitter at this account:</p>
 
 <p style="margin-left:2em;"><a href="http://twitter.com/androiddev">http://twitter.com/androiddev</a></p>
 
+<script type="text/javascript" src="https://plus.google.com/108967384991768947849"
+rel="publisher"></script>
+<script type="text/javascript">
+window.___gcfg = {lang: 'en'};
+(function() 
+{var po = document.createElement("script");
+po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
+var s = document.getElementsByTagName("script")[0];
+s.parentNode.insertBefore(po, s);
+})();</script>
\ No newline at end of file
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index 357c1ea..d55ab2b 100644
--- a/docs/html/resources/dashboard/opengl.jd
+++ b/docs/html/resources/dashboard/opengl.jd
@@ -57,7 +57,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A9.5,90.5" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1%20only|GL%202.0%20%26%201.1&chd=t%3A10.7,89.3" />
 
 <table>
 <tr>
@@ -65,15 +65,15 @@
 <th scope="col">Distribution</th>
 </tr>
 <tr>
-<td>1.1</th>
-<td>9.5%</td>
+<td>1.1 only</th>
+<td>10.7%</td>
 </tr>
 <tr>
-<td>2.0</th>
-<td>90.5%</td>
+<td>2.0 &amp; 1.1</th>
+<td>89.3%</td>
 </tr>
 </table>
 
-<p><em>Data collected during a 7-day period ending on January 3, 2012</em></p>
+<p><em>Data collected during a 7-day period ending on February 1, 2012</em></p>
 </div>
 
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 2618a04..4ea52af 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="470"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.6,1.1,8.5,30.4,0.6,54.9,0.1,1.5,1.7,0.3,0.3&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2|Android%204.0|Android%204.0.3&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.6,1.0,7.6,27.8,0.5,58.1,0.1,1.4,1.9,0.3,0.7&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2|Android%204.0|Android%204.0.3&chco=c4df9b,6fad0c" />
 
 <table>
 <tr>
@@ -62,24 +62,24 @@
   <th>Distribution</th>
 </tr>
 <tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td>  <td>3</td><td>0.6%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td>    <td>4</td><td>1.1%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td>   <td>7</td><td>8.5%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td>    <td>8</td><td>30.4%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td>    <td>4</td><td>1.0%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td>   <td>7</td><td>7.6%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td>    <td>8</td><td>27.8%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-2.3.html">Android 2.3 -<br/>
-                             Android 2.3.2</a></td><td rowspan="2">Gingerbread</td>    <td>9</td><td>0.6%</td></tr>
+                             Android 2.3.2</a></td><td rowspan="2">Gingerbread</td>    <td>9</td><td>0.5%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-2.3.3.html">Android 2.3.3 -<br/>
-      Android 2.3.7</a></td><!-- Gingerbread -->                                       <td>10</td><td>54.9%</td></tr>
+      Android 2.3.7</a></td><!-- Gingerbread -->                                       <td>10</td><td>58.1%</td></tr>
 <tr><td><a href="{@docRoot}sdk/android-3.0.html">Android 3.0</a></td>
                                                    <td rowspan="3">Honeycomb</td>      <td>11</td><td>0.1%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.5%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>1.7%</td></tr> 
+<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.4%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>1.9%</td></tr> 
 <tr><td><a href="{@docRoot}sdk/android-4.0.html">Android 4.0 -<br/>
                                                Android 4.0.2</a></td>
                                                 <td rowspan="2">Ice Cream Sandwich</td><td>14</td><td>0.3%</td></tr> 
-<tr><td><a href="{@docRoot}sdk/android-4.0.3.html">Android 4.0.3</a></td><!-- ICS     --><td>15</td><td>0.3%</td></tr> 
+<tr><td><a href="{@docRoot}sdk/android-4.0.3.html">Android 4.0.3</a></td><!-- ICS     --><td>15</td><td>0.7%</td></tr> 
 </table>
 
-<p><em>Data collected during a 14-day period ending on January 3, 2012</em></p>
+<p><em>Data collected during a 14-day period ending on February 1, 2012</em></p>
 <!--
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 -->
@@ -108,9 +108,9 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2012%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.2,99.0,98.8,98.7,98.5,98.5,98.2,98.1,98.0,99.9,99.9,99.7,99.2|97.7,97.6,97.5,97.5,97.5,97.5,97.1,97.1,97.0,99.1,99.1,99.0,98.6|95.5,95.5,95.5,95.6,95.7,95.8,95.6,95.9,95.7,97.7,97.8,97.8,97.5|77.6,79.0,80.2,81.1,82.4,83.3,83.8,84.9,85.1,87.5,88.2,88.6,89.0|17.8,20.6,24.3,27.5,31.2,34.7,38.3,41.3,44.0,48.9,52.9,55.7,58.5|16.8,20.0,23.7,26.9,30.6,34.1,37.8,40.8,43.5,48.4,52.4,55.2,57.9|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,2.3,2.6,3.2|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.2,1.3,1.7&chm=b,c3df9b,0,1,0|b,b8dc82,1,2,0|tAndroid 2.1,608920,2,0,15,,t::-5|b,addb67,2,3,0|tAndroid 2.2,517617,3,0,15,,t::-5|b,a3db4b,3,4,0|b,98dc2e,4,5,0|tAndroid 2.3.3,334d0a,5,0,15,,t::-5|b,8cd41b,5,6,0|b,7ec113,6,7,0|B,6fad0c,7,8,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3|Android 3.1|Android 3.2&chco=add274,a2d15a,97d13e,8bcb28,7dba1e,6ea715,5f920e,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2012%7C%7C2012%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:98.2,98.1,97.9,97.9,97.7,97.6,97.5,99.4,99.4,99.2,98.6,98.4,98.5|96.9,96.9,96.9,96.9,96.6,96.6,96.5,98.6,98.6,98.5,98.0,97.8,97.9|94.9,95.0,95.1,95.2,95.1,95.4,95.2,97.2,97.3,97.3,96.9,96.8,96.9|79.6,80.5,81.8,82.7,83.3,84.4,84.6,87.0,87.7,88.1,88.4,88.8,89.2|23.7,26.9,30.6,34.1,37.8,40.8,43.5,48.4,52.4,55.2,57.9,59.7,61.3|0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,2.3,2.6,3.2,3.2,3.3|0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.2,1.3,1.7,1.8,1.9&chm=b,c3df9b,0,1,0|b,b6dc7d,1,2,0|tAndroid%202.1,5b831d,2,0,15,,t::-5|b,aadb5e,2,3,0|tAndroid%202.2,496c13,3,0,15,,t::-5|b,9ddb3d,3,4,0|tAndroid%202.3.3,38540b,4,0,15,,t::-5|b,91da1e,4,5,0|b,80c414,5,6,0|B,6fad0c,6,7,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3.3|Android%203.1|Android%203.2&chco=add274,a0d155,94d134,84c323,73ad18,62960f,507d08" />
 
-<p><em>Last historical dataset collected during a 14-day period ending on January 3, 2012</em></p>
+<p><em>Last historical dataset collected during a 14-day period ending on February 1, 2012</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index 79d59d9..ae5cdc7 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -60,7 +60,7 @@
 <div class="dashboard-panel">
 
 <img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A3.1,0.1,3.1,71.0,1.0,17.5,2.9,1.3" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Normal%20/%20xhdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A4.8,0.2,2.9,67.1,0.7,18.4,1.8,2.5,1.6" />
 
 <table>
 <tr>
@@ -71,31 +71,31 @@
 <th scope="col">xhdpi</th>
 </tr>
 <tr><th scope="row">small</th> 
-<td>1.3%</td>     <!-- small/ldpi -->
+<td>1.6%</td>     <!-- small/ldpi -->
 <td></td>     <!-- small/mdpi -->
-<td>2.9%</td> <!-- small/hdpi -->
+<td>2.5%</td> <!-- small/hdpi -->
 <td></td>     <!-- small/xhdpi -->
 </tr> 
 <tr><th scope="row">normal</th> 
-<td>1.0%</td>  <!-- normal/ldpi -->
-<td>17.5%</td> <!-- normal/mdpi -->
-<td>71%</td> <!-- normal/hdpi -->
-<td></td>      <!-- normal/xhdpi -->
+<td>0.7%</td>  <!-- normal/ldpi -->
+<td>18.4%</td> <!-- normal/mdpi -->
+<td>67.1%</td> <!-- normal/hdpi -->
+<td>1.8%</td>      <!-- normal/xhdpi -->
 </tr> 
 <tr><th scope="row">large</th> 
-<td>0.1%</td>     <!-- large/ldpi -->
-<td>3.1%</td> <!-- large/mdpi -->
+<td>0.2%</td>     <!-- large/ldpi -->
+<td>2.9%</td> <!-- large/mdpi -->
 <td></td>     <!-- large/hdpi -->
 <td></td>     <!-- large/xhdpi -->
 </tr> 
 <tr><th scope="row">xlarge</th> 
 <td></td>     <!-- xlarge/ldpi -->
-<td>3.1%</td> <!-- xlarge/mdpi -->
+<td>4.8%</td> <!-- xlarge/mdpi -->
 <td></td>     <!-- xlarge/hdpi -->
 <td></td>     <!-- xlarge/xhdpi -->
 </tr> 
 </table>
 
-<p><em>Data collected during a 7-day period ending on December 1, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on February 1, 2012</em></p>
 </div>
 
diff --git a/docs/html/resources/faq/troubleshooting.jd b/docs/html/resources/faq/troubleshooting.jd
index 05a7ddab..f19f5ec 100644
--- a/docs/html/resources/faq/troubleshooting.jd
+++ b/docs/html/resources/faq/troubleshooting.jd
@@ -222,8 +222,8 @@
 
 <ol>
   <li>In a terminal, change to the tools directory of the SDK.</li>
-  <li>If no emulator instance is running, start an emulator using using the command <code>emulator &</code>.</li>
-  <li>Uninstall the preinstalled app using the command <code>adb uninstall com.android.samples</code>.</li>
+  <li>If no emulator instance is running, start an emulator using using the command <code>emulator</code>.</li>
+  <li>Uninstall the preinstalled app using the command <code>adb uninstall com.example.android.apis</code>.</li>
   <li>Reinstall the app using the command <code>adb install &lt;path to the ApiDemos.apk&gt;</code>. If you are 
   working in Eclipse/ADT, you can just compile and run the app in the normal way. </li>
 </ol>
diff --git a/docs/html/resources/resources_toc.cs b/docs/html/resources/resources_toc.cs
index 8df419f..8483037 100644
--- a/docs/html/resources/resources_toc.cs
+++ b/docs/html/resources/resources_toc.cs
@@ -1,7 +1,8 @@
 <ul>
   <li>
-    <h2><span class="en">Android Training</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Android Training</span>
+    </span>
     <ul>
       
       <li><a href="<?cs var:toroot ?>training/index.html">
@@ -237,8 +238,9 @@
       
       
   <li>
-    <h2><span class="en">Technical Resources</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Technical Resources</span>
+    </span>
     <ul>
       <li class="toggle-list">
         <div><a href="<?cs var:toroot ?>resources/browser.html?tag=sample">
@@ -288,29 +290,31 @@
     </ul>
   </li>
   <li>
-    <h2><span class="en">Community</span>
-               <span style="display:none" class="de"></span>
-               <span style="display:none" class="es">Comunidad</span>
-               <span style="display:none" class="fr">Communauté</span>
-               <span style="display:none" class="it"></span>
-               <span style="display:none" class="ja">コミュニティ</span>
-               <span style="display:none" class="zh-CN">社区</span>
-               <span style="display:none" class="zh-TW">社群</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Community</span>
+      <span style="display:none" class="de"></span>
+      <span style="display:none" class="es">Comunidad</span>
+      <span style="display:none" class="fr">Communauté</span>
+      <span style="display:none" class="it"></span>
+      <span style="display:none" class="ja">コミュニティ</span>
+      <span style="display:none" class="zh-CN">社区</span>
+      <span style="display:none" class="zh-TW">社群</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>resources/community-groups.html">
             <span class="en">Developer Forums</span>
           </a></li>
       <li><a href="<?cs var:toroot ?>resources/community-more.html">
-            <span class="en">IRC, Twitter</span>
+            <span class="en">IRC, G+, Twitter</span>
           </a></li>
     </ul>
   </li>
 <?cs
   if:android.whichdoc == "online" ?>
   <li>
-    <h2><span class="en">Device Dashboard</span>
-    </h2>
+    <span class="heading">
+      <span class="en">Device Dashboard</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>resources/dashboard/platform-versions.html">
             <span class="en">Platform Versions</span>
@@ -327,7 +331,9 @@
 ?>
 
   <li>
-   <h2><span class="en">More</span></h2>
+    <span class="heading">
+      <span class="en">More</span>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>resources/faq/commontasks.html">
             <span class="en">Common Tasks </span>
diff --git a/docs/html/resources/tutorials/hello-world.jd b/docs/html/resources/tutorials/hello-world.jd
index 9afab6a..cc8cb3e 100644
--- a/docs/html/resources/tutorials/hello-world.jd
+++ b/docs/html/resources/tutorials/hello-world.jd
@@ -24,7 +24,7 @@
 management to greatly speed up your development cycles.</p>
 
 <p>This tutorial assumes that you're using Eclipse. If you're using the command line, see
-<a href="{@docRoot}/guide/developing/building/building-cmdline.html">Building and Running from the
+<a href="{@docRoot}guide/developing/building/building-cmdline.html">Building and Running from the
 Command Line</a>. You can then return to this tutorial and ignore anything about Eclipse.</p>
 
 <p>Before you start, you should already have the SDK installed, and if you're
diff --git a/docs/html/resources/tutorials/notepad/notepad-ex2.jd b/docs/html/resources/tutorials/notepad/notepad-ex2.jd
index 7e3288f1..ed06778 100644
--- a/docs/html/resources/tutorials/notepad/notepad-ex2.jd
+++ b/docs/html/resources/tutorials/notepad/notepad-ex2.jd
@@ -87,8 +87,7 @@
     menu callback used for the options menu. Here, we add just one line, which will add a menu item
     to delete a note. Call <code>menu.add()</code> like so:
       <pre>
-public void onCreateContextMenu(Menu menu, View v,
-        ContextMenu.ContextMenuInfo menuInfo) {
+public void onCreateContextMenu(Menu menu, View v, ContextMenuInfo menuInfo) {
     super.onCreateContextMenu(menu, v, menuInfo);
     menu.add(0, DELETE_ID, 0, R.string.menu_delete);
 }</pre>
diff --git a/docs/html/resources/tutorials/opengl/opengl-es10.jd b/docs/html/resources/tutorials/opengl/opengl-es10.jd
index 3570766..2b44620 100644
--- a/docs/html/resources/tutorials/opengl/opengl-es10.jd
+++ b/docs/html/resources/tutorials/opengl/opengl-es10.jd
@@ -58,7 +58,7 @@
 needs. For more information, see
 <a href="{@docRoot}guide/topics/graphics/opengl.html#choosing-version">Choosing an OpenGL API
 Version</a>. If you would prefer to use OpenGL ES 2.0, see the <a
-href="{@docRoot}resources/tutorials/opengl/opengl-es20.jd">OpenGL ES 2.0 tutorial</a>.</p>
+href="{@docRoot}resources/tutorials/opengl/opengl-es20.html">OpenGL ES 2.0 tutorial</a>.</p>
 
 <p>Before you start, you should understand how to create a basic Android application. If you do not
 know how to create an app, follow the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello
diff --git a/docs/html/resources/tutorials/opengl/opengl-es20.jd b/docs/html/resources/tutorials/opengl/opengl-es20.jd
index 889dd50..dd23dbf 100644
--- a/docs/html/resources/tutorials/opengl/opengl-es20.jd
+++ b/docs/html/resources/tutorials/opengl/opengl-es20.jd
@@ -57,7 +57,7 @@
 needs. For more information, see
 <a href="{@docRoot}guide/topics/graphics/opengl.html#choosing-version">Choosing an OpenGL API
 Version</a>. If you would prefer to use OpenGL ES 1.0, see the <a
-href="{@docRoot}resources/tutorials/opengl/opengl-es10.jd">OpenGL ES 1.0 tutorial</a>.</p>
+href="{@docRoot}resources/tutorials/opengl/opengl-es10.html">OpenGL ES 1.0 tutorial</a>.</p>
 
 <p>Before you start, you should understand how to create a basic Android application. If you do not
 know how to create an app, follow the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello
diff --git a/docs/html/resources/tutorials/views/hello-mapview.jd b/docs/html/resources/tutorials/views/hello-mapview.jd
index 836d22c..ac5e826 100644
--- a/docs/html/resources/tutorials/views/hello-mapview.jd
+++ b/docs/html/resources/tutorials/views/hello-mapview.jd
@@ -255,7 +255,7 @@
 <pre>
 List&lt;Overlay> mapOverlays = mapView.getOverlays();
 Drawable drawable = this.getResources().getDrawable(R.drawable.androidmarker);
-HelloItemizedOverlay itemizedoverlay = new HelloItemizedOverlay(drawable);</pre>
+HelloItemizedOverlay itemizedoverlay = new HelloItemizedOverlay(drawable, this);</pre>
 
     <p>All overlay elements on a map are held by the {@code MapView}, so when you want to add some,
     you have to get a list from the <code>getOverlays()</code> method. Then instantiate the {@link
diff --git a/docs/html/sdk/android-2.3.3.jd b/docs/html/sdk/android-2.3.3.jd
index 7a5b044..023e2e4 100644
--- a/docs/html/sdk/android-2.3.3.jd
+++ b/docs/html/sdk/android-2.3.3.jd
@@ -336,7 +336,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-2.3.4.jd b/docs/html/sdk/android-2.3.4.jd
index 4cb44b9..eeaa69a 100644
--- a/docs/html/sdk/android-2.3.4.jd
+++ b/docs/html/sdk/android-2.3.4.jd
@@ -296,7 +296,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-2.3.jd b/docs/html/sdk/android-2.3.jd
index e7aa0fa..fc4f5aa 100644
--- a/docs/html/sdk/android-2.3.jd
+++ b/docs/html/sdk/android-2.3.jd
@@ -859,7 +859,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-3.0.jd b/docs/html/sdk/android-3.0.jd
index 96b92d9..49fefee 100644
--- a/docs/html/sdk/android-3.0.jd
+++ b/docs/html/sdk/android-3.0.jd
@@ -1119,7 +1119,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-3.1.jd b/docs/html/sdk/android-3.1.jd
index 78f265d..b9cf969 100644
--- a/docs/html/sdk/android-3.1.jd
+++ b/docs/html/sdk/android-3.1.jd
@@ -1040,7 +1040,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-4.0.3.jd b/docs/html/sdk/android-4.0.3.jd
index 1fca8df..809c83c 100644
--- a/docs/html/sdk/android-4.0.3.jd
+++ b/docs/html/sdk/android-4.0.3.jd
@@ -435,7 +435,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-4.0.jd b/docs/html/sdk/android-4.0.jd
index 5f55947..2cad86b 100644
--- a/docs/html/sdk/android-4.0.jd
+++ b/docs/html/sdk/android-4.0.jd
@@ -1963,7 +1963,7 @@
 <li>English, New Zealand (en_NZ)</li>
 <li>English, Singapore(en_SG)</li>
 <li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
 <li>Spanish (es_ES)</li>
 <li>Spanish, US (es_US)</li>
 <li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
index 44fe5e4..af25609 100644
--- a/docs/html/sdk/download.jd
+++ b/docs/html/sdk/download.jd
@@ -52,7 +52,7 @@
   <script language="javascript">
     var loc = window.location.href;
     if (loc.indexOf('?v=') != -1) {
-      var filename = loc.substring(loc.indexOf('=')+1,loc.length);
+      var filename = loc.substring(loc.indexOf('=')+1,loc.length).replace(/</g,"&lt;").replace(/>/g,"&gt;");
       document.write("File: " + filename);
     }
   </script>
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index f15da78..30825ee 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -42,7 +42,7 @@
 
 <p>Developing in Eclipse with ADT is highly recommended and is the fastest way
 to get started. With the guided project setup it provides, as well as tools
-integration, custom XML editors, and debug ouput pane, ADT gives you an
+integration, custom XML editors, and debug output pane, ADT gives you an
 incredible boost in developing Android applications. </p>
 
 <p>This document provides step-by-step instructions on how to download the ADT
@@ -1104,7 +1104,7 @@
 <h3 id="downloading">Downloading the ADT Plugin</h3>
 
 <p>Use the Update Manager feature of your Eclipse installation to install the latest
-revision of ADT on your development computer.<>
+revision of ADT on your development computer.</p>
 
 <p>Assuming that you have a compatible version of the Eclipse IDE installed, as
 described in <a href="#preparing">Preparing for Installation</a>, above, follow
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 65a1f46..5cf05e0 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -1,4 +1,5 @@
 page.title=Android SDK
+page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
 sdk.redirect=0
 
 sdk.win_installer=installer_r16-windows.exe
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index afbad57..29f0749 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,16 +1,16 @@
 ndk=true
 
-ndk.win_download=android-ndk-r7-windows.zip
-ndk.win_bytes=81270552
-ndk.win_checksum=55483482cf2b75e8dd1a5d9a7caeb6e5
+ndk.win_download=android-ndk-r7b-windows.zip
+ndk.win_bytes=80346206
+ndk.win_checksum=c42b0c9c14428397337421d5e4999380
 
-ndk.mac_download=android-ndk-r7-darwin-x86.tar.bz2
-ndk.mac_bytes=71262092
-ndk.mac_checksum=817ca5675a1dd44078098e43070f19b6
+ndk.mac_download=android-ndk-r7b-darwin-x86.tar.bz2
+ndk.mac_bytes=73817184
+ndk.mac_checksum=6daa82ca6b73bc0614c9997430079c7a
 
-ndk.linux_download=android-ndk-r7-linux-x86.tar.bz2
-ndk.linux_bytes=64884365
-ndk.linux_checksum=bf15e6b47bf50824c4b96849bf003ca3
+ndk.linux_download=android-ndk-r7b-linux-x86.tar.bz2
+ndk.linux_bytes=64349733
+ndk.linux_checksum=0eb8af18796cdaa082df8f7c54ad7f9a
 
 page.title=Android NDK
 
@@ -62,6 +62,116 @@
 <div class="toggleable open">
   <a href="#" onclick="return toggleDiv(this)"><img src=
   "{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px">
+  Android NDK, Revision 7b</a> <em>(February 2012)</em>
+
+  <div class="toggleme">
+    <p>This release of the NDK includes fixes for native Windows builds, Cygwin and many other
+      improvements:</p>
+
+    <dl>
+      <dt>Important bug fixes:</dt>
+
+      <dd>
+        <ul>
+          <li>Updated {@code sys/atomics.h} to avoid correctness issues
+            on some multi-core ARM-based devices. Rebuild your unmodified sources with this
+            version of the NDK and this problem should be completely eliminated.
+            For more details, read {@code docs/ANDROID-ATOMICS.html}.</li>
+          <li>Reverted to {@code binutils} 2.19 to fix debugging issues that
+            appeared in NDK r7 (which switched to {@code binutils} 2.20.1).</li>
+          <li>Fixed {@code ndk-build} on 32-bit Linux. A packaging error put a 64-bit version
+            of the {@code awk} executable under {@code prebuilt/linux-x86/bin} in NDK r7.</li>
+          <li>Fixed native Windows build ({@code ndk-build.cmd}). Other build modes were not
+            affected. The fixes include:
+            <ul>
+              <li>Removed an infinite loop / stack overflow bug that happened when trying
+                to call {@code ndk-build.cmd} from a directory that was <em>not</em> the top of
+                your project path (e.g., in any sub-directory of it).</li>
+              <li>Fixed a problem where the auto-generated dependency files were ignored. This
+                meant that updating a header didn't trigger recompilation of sources that included
+                it.</li>
+              <li>Fixed a problem where special characters in files or paths, other than spaces and
+                quotes, were not correctly handled.</li>
+            </ul>
+          </li>
+          <li>Fixed the standalone toolchain to generate proper binaries when using
+            {@code -lstdc++} (i.e., linking against the GNU {@code libstdc++} C++ runtime). You
+            should use {@code -lgnustl_shared} if you want to link against the shared library
+            version or {@code -lstdc++} for the static version.
+
+            <p>See {@code docs/STANDALONE-TOOLCHAIN.html} for more details about this fix.</p>
+          </li>
+          <li>Fixed {@code gnustl_shared} on Cygwin. The linker complained that it couldn't find
+            {@code libsupc++.a} even though the file was at the right location.</li>
+          <li>Fixed Cygwin C++ link when not using any specific C++ runtime through
+            {@code APP_STL}.</li>
+        </ul>
+      </dd>
+    </dl>
+
+    <dl>
+      <dt>Other changes:</dt>
+
+      <dd>
+        <ul>
+          <li>When your application uses the GNU {@code libstdc++} runtime, the compiler will
+            no longer forcibly enable exceptions and RTTI. This change results in smaller code.
+            <p>If you need these features, you must do one of the following:</p>
+            <ul>
+              <li>Enable exceptions and/or RTTI explicitly in your modules or
+                {@code Application.mk}. (recommended)</li>
+              <li>Define {@code APP_GNUSTL_FORCE_CPP_FEATURES} to {@code 'exceptions'},
+                {@code 'rtti'} or both in your {@code Application.mk}. See
+                {@code docs/APPLICATION-MK.html} for more details.</li>
+            </ul>
+          </li>
+          <li>{@code ndk-gdb} now works properly when your application has private services
+            running in independent processes. It debugs the main application process, instead of the
+            first process listed by {@code ps}, which is usually a service process.</li>
+          <li>Fixed a rare bug where NDK r7 would fail to honor the {@code LOCAL_ARM_MODE} value
+            and always compile certain source files (but not all) to 32-bit instructions.</li>
+          <li>{@code stlport}: Refresh the sources to match the Android platform version. This
+            update fixes a few minor bugs:
+            <ul>
+               <li>Fixed instantiation of an incomplete type</li>
+               <li>Fixed minor "==" versus "=" typo</li>
+               <li>Used {@code memmove} instead of {@code memcpy} in {@code string::assign}</li>
+               <li>Added better handling of {@code IsNANorINF}, {@code IsINF}, {@code IsNegNAN},
+                 etc.</li>
+             </ul>
+             <p>For complete details, see the commit log.</p>
+          </li>
+          <li>{@code stlport}: Removed 5 unnecessary static initializers from the library.</li>
+          <li>The GNU libstdc++ libraries for armeabi-v7a were mistakenly compiled for
+            armeabi instead. This change had no impact on correctness, but using the right
+            ABI should provide slightly better performance.</li>
+          <li>The {@code cpu-features} helper library was updated to report three optional
+            x86 CPU features ({@code SSSE3}, {@code MOVBE} and {@code POPCNT}). See
+            {@code docs/CPU-FEATURES.html} for more details.</li>
+          <li>{@code docs/NDK-BUILD.html} was updated to mention {@code NDK_APPLICATION_MK} instead
+            of {@code NDK_APP_APPLICATION_MK} to select a custom {@code Application.mk} file.</li>
+          <li>Cygwin: {@code ndk-build} no longer creates an empty "NUL" file in the current
+            directory when invoked.</li>
+          <li>Cygwin: Added better automatic dependency detection. In the previous version, it
+            didn't work properly in the following cases:
+            <ul>
+              <li>When the Cygwin drive prefix was not {@code /cygdrive}.</li>
+              <li>When using drive-less mounts, for example, when Cygwin would translate
+                {@code /home} to {@code \\server\subdir} instead of {@code C:\Some\Dir}.</li>
+            </ul>
+          </li>
+          <li>Cygwin: {@code ndk-build} does not try to use the native Windows tools under
+            {@code $NDK/prebuilt/windows/bin} with certain versions of Cygwin and/or GNU Make.</li>
+        </ul>
+      </dd>
+    </dl>
+  </div>
+</div>
+
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)"><img src=
+  "{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px">
   Android NDK, Revision 7</a> <em>(November 2011)</em>
 
   <div class="toggleme">
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 5f6a57f..f7541f7 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -1,7 +1,7 @@
 <?cs if:!sdk.redirect ?>
 <ul>
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">Android SDK Starter Package</span>
       <span style="display:none" class="de">Aktuelle SDK-Version</span>
       <span style="display:none" class="es">Versión actual del SDK</span>
@@ -10,7 +10,7 @@
       <span style="display:none" class="ja">現在リリースされている SDK</span>
       <span style="display:none" class="zh-CN">当前的 SDK 版本</span>
       <span style="display:none" class="zh-TW">目前 SDK 發行版本</span>
-    </h2>
+    </span>
     <ul><?cs
   if:android.whichdoc == "online" ?>
       <li><a href="<?cs var:toroot ?>sdk/index.html">
@@ -37,7 +37,8 @@
     </ul>
   </li><?cs
   if:sdk.preview ?>
-  <li><h2>Android 3.0 Preview SDK</h2>
+  <li>
+    <span class="heading">Android 3.0 Preview SDK</span>
     <ul>
       <li><a href="<?cs var:toroot ?>sdk/preview/start.html">Getting Started</a> <span
 class="new">new!</span></li>
@@ -46,13 +47,14 @@
   /if ?>
   <?cs
   if:sdk.preview ?>
-  <li><h2>Android x.x Preview</h2>
+  <li>
+    <span class="heading">Android x.x Preview</span>
     <ul>
     </ul>
   </li><?cs
   /if ?>
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">Downloadable SDK Components</span>
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
@@ -61,7 +63,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span>
-    </h2>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>sdk/adding-components.html">
       <span class="en">Adding SDK Components</span>
@@ -158,7 +160,7 @@
     </ul>
   </li>
   <li>
-      <h2>
+    <span class="heading">
       <span class="en">ADT Plugin for Eclipse</span>
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
@@ -167,7 +169,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span>
-      </h2>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 16.0.1
       <span style="display:none" class="de"></span>
@@ -182,7 +184,8 @@
     </ul>
   </li>
   <li>
-    <h2><span class="en">Native Development Tools</span>
+    <span class="heading">
+      <span class="en">Native Development Tools</span>
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
       <span style="display:none" class="fr"></span>
@@ -190,9 +193,9 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span>
-    </h2>
+    </span>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7</a>
+      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7b</a>
         <span class="new">new!</span>
         </li>
       <li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
@@ -200,7 +203,7 @@
   </li>
 
   <li>
-    <h2>
+    <span class="heading">
       <span class="en">More Information</span>
       <span style="display:none" class="de"></span>
       <span style="display:none" class="es"></span>
@@ -209,7 +212,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span>
-    </h2>
+    </span>
     <ul>
       <li><a href="<?cs var:toroot ?>sdk/oem-usb.html">
         <span class="en">OEM USB Drivers</span>
diff --git a/docs/html/shareables/adl/2010Q2_Business_Overview.pdf b/docs/html/shareables/adl/2010Q2_Business_Overview.pdf
deleted file mode 100644
index c34ea15..0000000
--- a/docs/html/shareables/adl/2010Q2_Business_Overview.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2010Q2_Market_Overview.pdf b/docs/html/shareables/adl/2010Q2_Market_Overview.pdf
deleted file mode 100644
index 3752258..0000000
--- a/docs/html/shareables/adl/2010Q2_Market_Overview.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2010Q2_SDK_Overview.pdf b/docs/html/shareables/adl/2010Q2_SDK_Overview.pdf
deleted file mode 100644
index 8796584..0000000
--- a/docs/html/shareables/adl/2010Q2_SDK_Overview.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf b/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
deleted file mode 100644
index 598a27e..0000000
--- a/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf b/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
deleted file mode 100644
index 6ef41dd..0000000
--- a/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
deleted file mode 100755
index e56d2377..0000000
--- a/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/icon_templates-v1.0.zip b/docs/html/shareables/icon_templates-v1.0.zip
deleted file mode 100644
index 94fbcdc..0000000
--- a/docs/html/shareables/icon_templates-v1.0.zip
+++ /dev/null
Binary files differ
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
index 0298a8e..cfbda2b 100644
--- a/docs/html/sitemap.txt
+++ b/docs/html/sitemap.txt
@@ -231,7 +231,6 @@
 http://developer.android.com/resources/samples/CubeLiveWallpaper/index.html
 http://developer.android.com/resources/samples/LunarLander/index.html
 http://developer.android.com/resources/samples/MultiResolution/index.html
-http://developer.android.com/resources/samples/NFCDemo/index.html
 http://developer.android.com/resources/samples/NotePad/index.html
 http://developer.android.com/resources/samples/SampleSyncAdapter/index.html
 http://developer.android.com/resources/samples/SearchableDictionary/index.html
@@ -1996,17 +1995,6 @@
 http://developer.android.com/reference/android/content/DialogInterface.html
 http://developer.android.com/reference/org/apache/http/message/BasicHeaderIterator.html
 http://developer.android.com/reference/org/apache/http/message/BasicListHeaderIterator.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/TagViewer.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/NdefMessageParser.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/ParsedNdefRecord.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/SmartPoster.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/TextRecord.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/UriRecord.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/simulator/FakeTagsActivity.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/simulator/MockNdefMessages.html
-http://developer.android.com/resources/samples/NFCDemo/res/index.html
-http://developer.android.com/resources/samples/NFCDemo/src/index.html
-http://developer.android.com/resources/samples/NFCDemo/AndroidManifest.html
 http://developer.android.com/reference/java/lang/InternalError.html
 http://developer.android.com/reference/java/lang/Error.html
 http://developer.android.com/reference/java/lang/VirtualMachineError.html
@@ -3039,7 +3027,6 @@
 http://developer.android.com/sdk/api_diff/3/changes/pkg_java.lang.html
 http://developer.android.com/sdk/api_diff/3/changes/pkg_java.util.jar.html
 http://developer.android.com/sdk/api_diff/3/changes/pkg_java.util.logging.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/index.html
 http://developer.android.com/sdk/api_diff/9/changes/alldiffs_index_removals.html
 http://developer.android.com/sdk/api_diff/9/changes/alldiffs_index_additions.html
 http://developer.android.com/sdk/api_diff/9/changes/alldiffs_index_changes.html
@@ -3514,7 +3501,6 @@
 http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/LabelView.html
 http://developer.android.com/resources/samples/ApiDemos/res/layout/custom_view_1.html
 http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/index.html
 http://developer.android.com/reference/org/apache/http/conn/ssl/SSLSocketFactory.html
 http://developer.android.com/reference/android/location/package-descr.html
 http://developer.android.com/resources/samples/AccessibilityService/res/values/strings.html
@@ -3939,10 +3925,6 @@
 http://developer.android.com/resources/samples/ContactManager/res/drawable-mdpi/icon.html
 http://developer.android.com/resources/samples/BackupRestore/src/com/example/index.html
 http://developer.android.com/reference/org/apache/http/message/package-descr.html
-http://developer.android.com/resources/samples/NFCDemo/res/drawable/index.html
-http://developer.android.com/resources/samples/NFCDemo/res/layout/index.html
-http://developer.android.com/resources/samples/NFCDemo/res/raw/index.html
-http://developer.android.com/resources/samples/NFCDemo/res/values/index.html
 http://developer.android.com/reference/android/bluetooth/package-descr.html
 http://developer.android.com/resources/samples/SipDemo/res/drawable/index.html
 http://developer.android.com/resources/samples/SipDemo/res/layout/index.html
@@ -4110,7 +4092,6 @@
 http://developer.android.com/sdk/api_diff/9/changes/methods_index_additions.html
 http://developer.android.com/sdk/api_diff/9/changes/methods_index_changes.html
 http://developer.android.com/reference/android/media/audiofx/package-descr.html
-http://developer.android.com/resources/samples/NFCDemo/res/values/strings.html
 http://developer.android.com/reference/android/sax/ElementListener.html
 http://developer.android.com/reference/android/sax/EndElementListener.html
 http://developer.android.com/reference/android/sax/EndTextElementListener.html
@@ -4599,7 +4580,6 @@
 http://developer.android.com/reference/android/text/method/package-descr.html
 http://developer.android.com/resources/samples/JetBoy/JETBOY_content/JETBOY_Music.logic/LgDoc/index.html
 http://developer.android.com/resources/samples/TicTacToeMain/res/layout/main.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/index.html
 http://developer.android.com/resources/samples/SearchableDictionary/res/drawable-mdpi/ic_menu_search.html
 http://developer.android.com/resources/samples/TicTacToeMain/res/values/strings.html
 http://developer.android.com/sdk/api_diff/7/changes/alldiffs_index_additions.html
@@ -4637,9 +4617,6 @@
 http://developer.android.com/resources/samples/SoftKeyboard/res/values-land/index.html
 http://developer.android.com/resources/samples/SoftKeyboard/res/xml/index.html
 http://developer.android.com/reference/junit/runner/package-descr.html
-http://developer.android.com/resources/samples/NFCDemo/res/layout/tag_divider.html
-http://developer.android.com/resources/samples/NFCDemo/res/layout/tag_text.html
-http://developer.android.com/resources/samples/NFCDemo/res/layout/tag_viewer.html
 http://developer.android.com/resources/samples/AccelerometerPlay/res/drawable-ldpi/icon.html
 http://developer.android.com/resources/samples/CubeLiveWallpaper/src/com/example/index.html
 http://developer.android.com/reference/android/text/style/package-descr.html
@@ -4726,14 +4703,12 @@
 http://developer.android.com/sdk/api_diff/3/changes/classes_index_additions.html
 http://developer.android.com/sdk/api_diff/3/changes/classes_index_changes.html
 http://developer.android.com/resources/samples/WiktionarySimple/src/com/index.html
-http://developer.android.com/resources/samples/NFCDemo/res/drawable/icon.html
 http://developer.android.com/resources/samples/SearchableDictionary/res/drawable-hdpi/ic_menu_search.html
 http://developer.android.com/resources/samples/SipDemo/res/values/strings.html
 http://developer.android.com/resources/samples/SpinnerTest/src/com/android/index.html
 http://developer.android.com/sdk/api_diff/3/changes/methods_index_removals.html
 http://developer.android.com/sdk/api_diff/3/changes/methods_index_additions.html
 http://developer.android.com/sdk/api_diff/3/changes/methods_index_changes.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/index.html
 http://developer.android.com/resources/samples/SoftKeyboard/res/xml/method.html
 http://developer.android.com/resources/samples/SoftKeyboard/res/xml/qwerty.html
 http://developer.android.com/resources/samples/SoftKeyboard/res/xml/symbols.html
@@ -5326,8 +5301,6 @@
 http://developer.android.com/sdk/api_diff/5/changes/alldiffs_index_removals.html
 http://developer.android.com/sdk/api_diff/5/changes/alldiffs_index_additions.html
 http://developer.android.com/sdk/api_diff/5/changes/alldiffs_index_changes.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/index.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/simulator/index.html
 http://developer.android.com/resources/samples/BackupRestore/src/com/example/android/index.html
 http://developer.android.com/resources/samples/BluetoothChat/src/com/example/android/BluetoothChat/index.html
 http://developer.android.com/resources/samples/ContactManager/src/com/example/android/index.html
diff --git a/docs/html/training/design-navigation/ancestral-temporal.jd b/docs/html/training/design-navigation/ancestral-temporal.jd
index 02e43e1..ab6a64d 100644
--- a/docs/html/training/design-navigation/ancestral-temporal.jd
+++ b/docs/html/training/design-navigation/ancestral-temporal.jd
@@ -21,6 +21,7 @@
 
 <h2>You should also read</h2>
 <ul>
+  <li><a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a></li>
   <li><a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a></li>
 </ul>
 
@@ -28,32 +29,65 @@
 </div>
 
 
-<p>Now that users can navigate <a href="descendant-lateral.html">deep into</a> the application's screen hierarchy, we need to provide a method for navigating up the hierarchy, to parent and ancestor screens. Additionally, we should ensure that temporal navigation via the BACK button is respected to respect Android conventions.</p>
+<p>Now that users can navigate <a href="descendant-lateral.html">deep into</a> the application's
+screen hierarchy, we need to provide a method for navigating up the hierarchy, to parent and
+ancestor screens. Additionally, we should ensure that temporal navigation via the <em>Back</em>
+button is respected to respect Android conventions.</p>
 
+<div class="design-announce">
+<p><strong>Back/Up Navigation Design</strong></p>
+  <p>For design guidelines, read Android Design's <a
+  href="{@docRoot}design/patterns/navigation.html">Navigation</a> pattern guide.</p>
+</div>
 
 <h2 id="temporal-navigation">Support Temporal Navigation: <em>Back</em></h2>
 
-<p>Temporal navigation, or navigation between historical screens, is deeply rooted in the Android system. All Android users expect the BACK button to take them to the previous screen, regardless of other state. The set of historical screens is always rooted at the user's Launcher application (the phone's "home" screen). That is, pressing BACK enough times should land you back at the Launcher, after which the BACK button will do nothing.</p>
+<p>Temporal navigation, or navigation between historical screens, is deeply rooted in the Android
+system. All Android users expect the <em>Back</em> button to take them to the previous screen,
+regardless of other state. The set of historical screens is always rooted at the user's Launcher
+application (the phone's "home" screen). That is, pressing <em>Back</em> enough times should land
+you back at the Launcher, after which the <em>Back</em> button will do nothing.</p>
 
 
 <img src="{@docRoot}images/training/app-navigation-ancestral-navigate-back.png"
-  alt="The BACK button behavior after entering the Email app from the People (or Contacts) app" id="figure-navigate-back">
+  alt="The Back button behavior after entering the Email app from the People (or Contacts) app"
+id="figure-navigate-back">
 
-<p class="img-caption"><strong>Figure 1.</strong> The BACK button behavior after entering the Email app from the People (or Contacts) app.</p>
+<p class="img-caption"><strong>Figure 1.</strong> The <em>Back</em> button behavior after entering
+the Email app from the People (or Contacts) app.</p>
 
 
-<p>Applications generally don't have to worry about managing the BACK button themselves; the system handles <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">tasks and the <em>back stack</em></a>, or the list of previous screens, automatically. The BACK button by default simply traverses this list of screens, removing the current screen from the list upon being pressed.</p>
+<p>Applications generally don't have to worry about managing the <em>Back</em> button themselves;
+the system handles <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">tasks and
+the <em>back stack</em></a>, or the list of previous screens, automatically. The <em>Back</em>
+button by default simply traverses this list of screens, removing the current screen from the list
+upon being pressed.</p>
 
-<p>There are, however, cases where you may want to override the behavior for BACK. For example, if your screen contains an embedded web browser where users can interact with page elements to navigate between web pages, you may wish to trigger the embedded browser's default <em>back</em> behavior when users press the device's BACK button. Upon reaching the beginning of the browser's internal history, you should always defer to the system's default behavior for the BACK button.</p>
+<p>There are, however, cases where you may want to override the behavior for <em>Back</em>. For
+example, if your screen contains an embedded web browser where users can interact with page elements
+to navigate between web pages, you may wish to trigger the embedded browser's default <em>back</em>
+behavior when users press the device's <em>Back</em> button. Upon reaching the beginning of the
+browser's internal history, you should always defer to the system's default behavior for the
+<em>Back</em> button.</p>
 
 
 <h2 id="ancestral-navigation">Provide Ancestral Navigation: <em>Up</em> and <em>Home</em></h2>
 
-<p>Before Android 3.0, the most common form of ancestral navigation was the <em>Home</em> metaphor. This was generally implemented as a <em>Home</em> item accessible via the device's MENU button, or a <em>Home</em> button at the top-left of the screen, usually as a component of the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>. Upon selecting <em>Home</em>, the user would be taken to the screen at the top of the screen hierarchy, generally known as the application's home screen.</p>
+<p>Before Android 3.0, the most common form of ancestral navigation was the <em>Home</em> metaphor.
+This was generally implemented as a <em>Home</em> item accessible via the device's <em>Menu</em>
+button, or a <em>Home</em> button at the top-left of the screen, usually as a component of the
+Action Bar (<a href="{@docRoot}design/patterns/actionbar.html">pattern docs</a> at Android Design).
+Upon selecting <em>Home</em>, the user would be taken to the screen at the top of the screen
+hierarchy, generally known as the application's home screen.</p>
 
 <p>Providing direct access to the application's home screen can give the user a sense of comfort and security. Regardless of where they are in the application, if they get lost in the app, they can select <em>Home</em> to arrive back at the familiar home screen.</p>
 
-<p>Android 3.0 introduced the <em>Up</em> metaphor, which is presented in the Action Bar as a substitute for the <em>Home</em> button described above. Upon tapping <em>Up</em>, the user should be taken to the parent screen in the hierarchy. This navigation step is usually the previous screen (as described with the BACK button discussion above), but this is not universally the case. Thus, developers must ensure that <em>Up</em> for each screen navigates to a single, predetermined parent screen.</p>
+<p>Android 3.0 introduced the <em>Up</em> metaphor, which is presented in the Action Bar as a
+substitute for the <em>Home</em> button described above. Upon tapping <em>Up</em>, the user should
+be taken to the parent screen in the hierarchy. This navigation step is usually the previous screen
+(as described with the <em>Back</em> button discussion above), but this is not universally the case.
+Thus, developers must ensure that <em>Up</em> for each screen navigates to a single, predetermined
+parent screen.</p>
 
 
 <img src="{@docRoot}images/training/app-navigation-ancestral-navigate-up.png"
@@ -64,6 +98,12 @@
 
 <p>In some cases, it's appropriate for <em>Up</em> to perform an action rather than navigating to a parent screen. Take for example, the Gmail application for Android 3.0-based tablets. When viewing a mail conversation while holding the device in landscape, the conversation list, as well as the conversation details are presented side-by-side. This is a form of parent-child screen grouping, as discussed in a <a href="multiple-sizes.html">previous lesson</a>. However, when viewing a mail conversation in the portrait orientation, only the conversation details are shown. The <em>Up</em> button is used to temporarily show the parent pane, which slides in from the left of the screen. Pressing the <em>Up</em> button again while the left pane is visible exits the context of the individual conversation, up to a full-screen list of conversations.</p>
 
-<p class="note"><strong>Implementation Note:</strong> As a best practice, when implementing either <em>Home</em> or <em>Up</em>, make sure to clear the back stack of any descendent screens. For <em>Home</em>, the only remaining screen on the back stack should be the home screen. For <em>Up</em> navigation, the current screen should be removed from the back stack, unless BACK navigates across screen hierarchies. You can use the {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} and {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} intent flags together to achieve this.</p>
+<p class="note"><strong>Implementation Note:</strong> As a best practice, when implementing either
+<em>Home</em> or <em>Up</em>, make sure to clear the back stack of any descendent screens. For
+<em>Home</em>, the only remaining screen on the back stack should be the home screen. For
+<em>Up</em> navigation, the current screen should be removed from the back stack, unless
+<em>Back</em> navigates across screen hierarchies. You can use the {@link
+android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP} and {@link
+android.content.Intent#FLAG_ACTIVITY_NEW_TASK} intent flags together to achieve this.</p>
 
 <p>In the last lesson, we apply the concepts discussed in all of the lessons so far to create interaction design wireframes for our example news application.</p>
diff --git a/docs/html/training/design-navigation/descendant-lateral.jd b/docs/html/training/design-navigation/descendant-lateral.jd
index ebfd913..2d97e40 100644
--- a/docs/html/training/design-navigation/descendant-lateral.jd
+++ b/docs/html/training/design-navigation/descendant-lateral.jd
@@ -18,9 +18,18 @@
   <li><a href="#buttons">Buttons and Simple Targets</a></li>
   <li><a href="#lists">Lists, Grids, Carousels, and Stacks</a></li>
   <li><a href="#tabs">Tabs</a></li>
-  <li><a href="#paging">Horizontal Paging</a></li>
+  <li><a href="#paging">Horizontal Paging (Swipe Views)</a></li>
 </ol>
 
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}design/building-blocks/buttons.html">Android Design: Buttons</a></li>
+  <li><a href="{@docRoot}design/building-blocks/lists.html">Android Design: Lists</a></li>
+  <li><a href="{@docRoot}design/building-blocks/grid-lists.html">Android Design: Grid Lists</a></li>
+  <li><a href="{@docRoot}design/building-blocks/tabs.html">Android Design: Tabs</a></li>
+  <li><a href="{@docRoot}design/patterns/swipe-views.html">Android Design: Swipe Views</a></li>
+</ul>
+
 </div>
 </div>
 
@@ -48,6 +57,12 @@
 
 <h2 id="buttons">Buttons and Simple Targets</h2>
 
+<div class="design-announce">
+<p><strong>Button Design</strong></p>
+  <p>For design guidelines, read Android Design's <a
+  href="{@docRoot}design/building-blocks/buttons.html">Buttons</a> guide.</p>
+</div>
+
 <p>For section-related screens, offering touchable and keyboard-focusable targets in the parent is generally the most straightforward and familiar kind of touch-based navigation interface. Examples of such targets include buttons, fixed-size list views, or text links, although the latter is not an ideal UI (user interface) element for touch-based navigation. Upon selecting one of these targets, the child screen is opened, replacing the current context (screen) entirely. Buttons and other simple targets are rarely used for representing items in a collection.</p>
 
 
@@ -64,6 +79,13 @@
 
 <h2 id="lists">Lists, Grids, Carousels, and Stacks</h2>
 
+<div class="design-announce">
+<p><strong>List and Grid List Design</strong></p>
+  <p>For design guidelines, read Android Design's <a
+  href="{@docRoot}design/building-blocks/lists.html">Lists</a> and <a
+  href="{@docRoot}design/building-blocks/grid-lists.html">Grid Lists</a> guides.</p>
+</div>
+
 <p>For collection-related screens, and especially for textual information, vertically scrolling lists are often the most straightforward and familiar kind of interface. For more visual or media-rich content items such as photos or videos, vertically scrolling grids of items, horizontally scrolling lists (sometimes referred to as <em>carousels</em>), or stacks (sometimes referred to as <em>cards</em>) can be used instead. These UI elements are generally best used for presenting item collections or large sets of child screens (for example, a list of stories or a list of 10 or more news topics), rather than a small set of unrelated, sibling child screens.</p>
 
 
@@ -80,6 +102,12 @@
 
 <h2 id="tabs">Tabs</h2>
 
+<div class="design-announce">
+<p><strong>Tab Design</strong></p>
+  <p>For design guidelines, read Android Design's <a
+  href="{@docRoot}design/building-blocks/tabs.html">Tabs</a> guide.</p>
+</div>
+
 <p>Using tabs is a very popular solution for lateral navigation. This pattern allows grouping of sibling screens, in that the tab content container in the parent screen can embed child screens that otherwise would be entirely separate contexts. Tabs are most appropriate for small sets (4 or fewer) of section-related screens.</p>
 
 
@@ -89,7 +117,16 @@
 <p class="img-caption"><strong>Figure 5.</strong> Example phone and tablet tab-based navigation interfaces with relevant screen map excerpt.</p>
 
 
-<p>Several best practices apply when using tabs. Tabs should be persistent across immediate related screens. Only the designated content region should change when selecting a tab, and tab indicators should remain available at all times. Additionally, tab switches should not be treated as history. For example, if a user switches from a tab <em>A</em> to another tab <em>B</em>, pressing the BACK button (more on that in the <a href="ancestral-temporal.html">next lesson</a>) should not re-select tab <em>A</em>. Tabs are usually laid out horizontally, although other presentations of tab navigation such as using a drop-down list in the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> are sometimes appropriate. Lastly, and most importantly, <em>tabs should always run along the top of the screen</em>, and should not be aligned to the bottom of the screen.</p>
+<p>Several best practices apply when using tabs. Tabs should be persistent across immediate related
+screens. Only the designated content region should change when selecting a tab, and tab indicators
+should remain available at all times. Additionally, tab switches should not be treated as history.
+For example, if a user switches from a tab <em>A</em> to another tab <em>B</em>, pressing the
+<em>Back</em> button (more on that in the <a href="ancestral-temporal.html">next lesson</a>) should
+not re-select tab <em>A</em>. Tabs are usually laid out horizontally, although other presentations
+of tab navigation such as using a drop-down list in the Action Bar (<a
+href="{@docRoot}design/patterns/actionbar.html">pattern docs</a> at Android Design) are sometimes
+appropriate. Lastly, and most importantly, <em>tabs should always run along the top of the
+screen</em>, and should not be aligned to the bottom of the screen.</p>
 
 <p>There are some obvious immediate benefits of tabs over simpler list- and button-based navigation:</p>
 
@@ -101,9 +138,15 @@
 <p>A common criticism is that space must be reserved for the tab indicators, detracting from the space available to tab contents. This consequence is usually acceptable, and the tradeoff commonly weighs in favor of using this pattern. You should also feel free to customize tab indicators, showing text and/or icons to make optimal use of vertical space. When adjusting indicator heights however, ensure that tab indicators are large enough for a human finger to touch without error.</p>
 
 
-<h2 id="paging">Horizontal Paging</h2>
+<h2 id="paging">Horizontal Paging (Swipe Views)</h2>
 
-<p>Another popular lateral navigation pattern is horizontal paging. This pattern applies best to collection-related sibling screens, such as a list of categories (world, business, technology, and health stories). Like tabs, this pattern also allows grouping screens in that the parent presents the contents of child screens embedded within its own layout.</p>
+<div class="design-announce">
+<p><strong>Swipe Views Design</strong></p>
+  <p>For design guidelines, read Android Design's <a
+  href="{@docRoot}design/patterns/swipe-views.html">Swipe Views</a> pattern guides.</p>
+</div>
+
+<p>Another popular lateral navigation pattern is horizontal paging, also referred to as swipe views. This pattern applies best to collection-related sibling screens, such as a list of categories (world, business, technology, and health stories). Like tabs, this pattern also allows grouping screens in that the parent presents the contents of child screens embedded within its own layout.</p>
 
 
 <img src="{@docRoot}images/training/app-navigation-descendant-lateral-paging.png"
diff --git a/docs/html/training/design-navigation/index.jd b/docs/html/training/design-navigation/index.jd
index e02d52e..af60717 100644
--- a/docs/html/training/design-navigation/index.jd
+++ b/docs/html/training/design-navigation/index.jd
@@ -14,7 +14,7 @@
 
 <p>This class is not specific to any particular version of the Android platform. It is also primarily design-focused and does not require knowledge of the Android SDK. That said, you should have experience using an Android device for a better understanding of the context in which Android applications run.</p>
 
-<p>You should also have basic familiarity with the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>, used across most applications in devices running Android 3.0 and later.</p>
+<p>You should also have basic familiarity with the Action Bar (<a href="{@docRoot}design/patterns/actionbar.html">pattern docs</a> at Android Design), used across most applications in devices running Android 3.0 and later.</p>
 
 
 </div>
@@ -41,7 +41,9 @@
     <dd>Learn about techniques for allowing users to navigate deep into, as well as across, your content hierarchy. Also learn about pros and cons of, and best practices for, specific navigational UI elements for various situations.</dd>
 
   <dt><strong><a href="ancestral-temporal.html">Providing Ancestral and Temporal Navigation</a></strong></dt>
-    <dd>Learn how to allow users to navigate upwards in the content hierarchy. Also learn about best practices for the BACK button and temporal navigation, or navigation to previous screens that may not be hierarchically related.</dd>
+    <dd>Learn how to allow users to navigate upwards in the content hierarchy. Also learn about best
+practices for the <em>Back</em> button and temporal navigation, or navigation to previous screens
+that may not be hierarchically related.</dd>
 
   <dt><strong><a href="wireframing.html">Putting it All Together: Wireframing the Example App</a></strong></dt>
     <dd>Learn how to create screen wireframes (low-fidelity graphic mockups) representing the screens in a news application based on the desired information model. These wireframes utilize navigational elements discussed in previous lessons to demonstrate intuitive and efficient navigation.</dd>
diff --git a/docs/html/training/design-navigation/multiple-sizes.jd b/docs/html/training/design-navigation/multiple-sizes.jd
index 7a8139f..ebaec0f 100644
--- a/docs/html/training/design-navigation/multiple-sizes.jd
+++ b/docs/html/training/design-navigation/multiple-sizes.jd
@@ -22,6 +22,7 @@
 
 <h2>You should also read</h2>
 <ul>
+  <li><a href="{@docRoot}design/patterns/multi-pane-layouts.html">Android Design: Multi-pane Layouts</a></li>
   <li><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a></li>
 </ul>
 
@@ -35,6 +36,12 @@
 
 <h2 id="multi-pane-layouts">Group Screens with Multi-pane Layouts</h2>
 
+<div class="design-announce">
+<p><strong>Multi-pane Layout Design</strong></p>
+  <p>For design guidelines, read Android Design's <a
+  href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane Layouts</a> pattern guide.</p>
+</div>
+
 <p>3 to 4-inch screens are generally only suitable for showing a single vertical pane of content at a time, be it a list of items, or detail information about an item, etc. Thus on such devices, screens generally map one-to-one with levels in the information hierarchy (<em>categories</em> &rarr; <em>object list</em> &rarr; <em>object detail</em>).</p>
 
 <p>Larger screens such as those found on tablets and TVs, on the other hand, generally have much more available screen space and are able to present multiple panes of content. In landscape, panes are usually ordered from left to right in increasing detail order. Users are especially accustomed to multiple panes on larger screens from years and years of desktop application and desktop web site use. Many desktop applications and websites offer a left-hand navigation pane or use a master/detail two-pane layout.</p>
@@ -76,12 +83,12 @@
   <li><strong>Expand/collapse</strong>
     <img src="{@docRoot}images/training/app-navigation-multiple-sizes-strategy-collapse.png"
       alt="Expand/collapse strategy">
-    <p>A variation on the stretch strategy is to collapse the contents of the left pane when in portrait. This works quite well with master/detail panes where the left (master) pane contains easily collapsible list items. An example would be for a realtime chat application. In landscape, the left list could contain chat contact photos, names, and online statuses. In portrait, horizontal space could be collapsed by hiding contact names and only showing photos and online status indicator icons.</p></li>
+    <p>A variation on the stretch strategy is to collapse the contents of the left pane when in portrait. This works quite well with master/detail panes where the left (master) pane contains easily collapsible list items. An example would be for a realtime chat application. In landscape, the left list could contain chat contact photos, names, and online statuses. In portrait, horizontal space could be collapsed by hiding contact names and only showing photos and online status indicator icons. Optionally also provide an expand control that allows the user to expand the left pane content to its larger width and vice versa.</p></li>
 
   <li><strong>Show/Hide</strong>
     <img src="{@docRoot}images/training/app-navigation-multiple-sizes-strategy-show-hide.png"
       alt="Show/Hide strategy">
-    <p>In this scenario, the left pane is completely hidden in portrait mode. However, <em>to ensure the functional parity</em> of your screen in portrait and landscape, the left pane should be made available via an onscreen affordance (such as a button). It's usually appropriate to use the <em>Up</em> button in the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> to show the left pane, as is discussed in a <a href="ancestral-temporal.html">later lesson</a>.</p></li>
+    <p>In this scenario, the left pane is completely hidden in portrait mode. However, <em>to ensure the functional parity</em> of your screen in portrait and landscape, the left pane should be made available via an onscreen affordance (such as a button). It's usually appropriate to use the <em>Up</em> button in the Action Bar (<a href="{@docRoot}design/patterns/actionbar.html">pattern docs</a> at Android Design) to show the left pane, as is discussed in a <a href="ancestral-temporal.html">later lesson</a>.</p></li>
 
   <li><strong>Stack</strong>
     <img src="{@docRoot}images/training/app-navigation-multiple-sizes-strategy-stack.png"
diff --git a/docs/html/training/design-navigation/wireframing.jd b/docs/html/training/design-navigation/wireframing.jd
index c7687dd..6deceb1 100644
--- a/docs/html/training/design-navigation/wireframing.jd
+++ b/docs/html/training/design-navigation/wireframing.jd
@@ -121,5 +121,5 @@
   <li><a href="{@docRoot}guide/topics/ui/index.html">Developer's Guide: User Interface</a>: learn how to implement your user interface designs using the Android SDK.</li>
   <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>: implement tabs, up navigation, on-screen actions, etc.
   <li><a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a>: implement re-usable, multi-pane layouts
-  <li><a href="{@docRoot}sdk/compatibility-library.html">Support Library</a>: implement horizontal paging using <code>ViewPager</code></li>
+  <li><a href="{@docRoot}sdk/compatibility-library.html">Support Library</a>: implement horizontal paging (swipe views) using <code>ViewPager</code></li>
 </ul>
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 8d17561..bff2a76 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -518,15 +518,16 @@
         byte[] np = bm.getNinePatchChunk();
         final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
         if (opts.inScaled || isNinePatch) {
-            float scale = targetDensity / (float)density;
-            // TODO: This is very inefficient and should be done in native by Skia
-            final Bitmap oldBitmap = bm;
-            bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
-                    (int) (bm.getHeight() * scale + 0.5f), true);
-            oldBitmap.recycle();
+            float scale = targetDensity / (float) density;
+            if (scale != 1.0f) {
+                final Bitmap oldBitmap = bm;
+                bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
+                        (int) (bm.getHeight() * scale + 0.5f), true);
+                if (bm != oldBitmap) oldBitmap.recycle();
+            }
 
             if (isNinePatch) {
-                np = nativeScaleNinePatch(np, scale, outPadding);
+                if (scale != 1.0f) np = nativeScaleNinePatch(np, scale, outPadding);
                 bm.setNinePatchChunk(np);
             }
             bm.setDensity(targetDensity);
diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java
index 82ed199..96a71e3 100644
--- a/graphics/java/android/graphics/LinearGradient.java
+++ b/graphics/java/android/graphics/LinearGradient.java
@@ -28,8 +28,8 @@
                             the the colors are distributed evenly along the gradient line.
         @param  tile        The Shader tiling mode
 	*/
-	public LinearGradient(float x0, float y0, float x1, float y1,
-                          int colors[], float positions[], TileMode tile) {
+	public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
+            TileMode tile) {
         if (colors.length < 2) {
             throw new IllegalArgumentException("needs >= 2 number of colors");
         }
@@ -50,8 +50,8 @@
         @param  color1  The color at the end of the gradient line.
         @param  tile    The Shader tiling mode
 	*/
-	public LinearGradient(float x0, float y0, float x1, float y1,
-                          int color0, int color1, TileMode tile) {
+	public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
+            TileMode tile) {
         native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
         native_shader = nativePostCreate2(native_instance, x0, y0, x1, y1, color0, color1,
                 tile.nativeInt);
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 7830224..0ada1fb 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -76,13 +76,21 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
-        Rect r = (Rect) obj;
-        if (r != null) {
-            return left == r.left && top == r.top && right == r.right
-                    && bottom == r.bottom;
-        }
-        return false;
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Rect r = (Rect) o;
+        return left == r.left && top == r.top && right == r.right && bottom == r.bottom;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = left;
+        result = 31 * result + top;
+        result = 31 * result + right;
+        result = 31 * result + bottom;
+        return result;
     }
 
     @Override
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index 00e9609..293dfcc 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -79,6 +79,24 @@
         bottom = r.bottom;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Rect r = (Rect) o;
+        return left == r.left && top == r.top && right == r.right && bottom == r.bottom;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = (left != +0.0f ? Float.floatToIntBits(left) : 0);
+        result = 31 * result + (top != +0.0f ? Float.floatToIntBits(top) : 0);
+        result = 31 * result + (right != +0.0f ? Float.floatToIntBits(right) : 0);
+        result = 31 * result + (bottom != +0.0f ? Float.floatToIntBits(bottom) : 0);
+        return result;
+    }
+
     public String toString() {
         return "RectF(" + left + ", " + top + ", "
                       + right + ", " + bottom + ")";
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 50964d5..5b50beb 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -173,9 +173,20 @@
     }
 
     /**
-     * Specify radii for each of the 4 corners. For each corner, the array
-     * contains 2 values, [X_radius, Y_radius]. The corners are ordered
-     * top-left, top-right, bottom-right, bottom-left
+     * <p>Specify radii for each of the 4 corners. For each corner, the array
+     * contains 2 values, <code>[X_radius, Y_radius]</code>. The corners are ordered
+     * top-left, top-right, bottom-right, bottom-left. This property
+     * is honored only when the shape is of type {@link #RECTANGLE}.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param radii 4 pairs of X and Y radius for each corner, specified in pixels.
+     *              The length of this array must be >= 8
+     *
+     * @see #mutate()
+     * @see #setCornerRadii(float[])
+     * @see #setShape(int)
      */
     public void setCornerRadii(float[] radii) {
         mGradientState.setCornerRadii(radii);
@@ -184,23 +195,57 @@
     }
     
     /**
-     * Specify radius for the corners of the gradient. If this is > 0, then the
-     * drawable is drawn in a round-rectangle, rather than a rectangle.
+     * <p>Specify radius for the corners of the gradient. If this is > 0, then the
+     * drawable is drawn in a round-rectangle, rather than a rectangle. This property
+     * is honored only when the shape is of type {@link #RECTANGLE}.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param radius The radius in pixels of the corners of the rectangle shape
+     *
+     * @see #mutate()
+     * @see #setCornerRadii(float[])
+     * @see #setShape(int) 
      */
     public void setCornerRadius(float radius) {
         mGradientState.setCornerRadius(radius);
         mPathIsDirty = true;
         invalidateSelf();
     }
-    
+
     /**
-     * Set the stroke width and color for the drawable. If width is zero,
-     * then no stroke is drawn.
+     * <p>Set the stroke width and color for the drawable. If width is zero,
+     * then no stroke is drawn.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param width The width in pixels of the stroke
+     * @param color The color of the stroke
+     *
+     * @see #mutate()
+     * @see #setStroke(int, int, float, float) 
      */
     public void setStroke(int width, int color) {
         setStroke(width, color, 0, 0);
     }
-    
+
+    /**
+     * <p>Set the stroke width and color for the drawable. If width is zero,
+     * then no stroke is drawn. This method can also be used to dash the stroke.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param width The width in pixels of the stroke
+     * @param color The color of the stroke
+     * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes 
+     * @param dashGap The gap in pixels between dashes
+     *
+     * @see #mutate()
+     * @see #setStroke(int, int) 
+     */
     public void setStroke(int width, int color, float dashWidth, float dashGap) {
         mGradientState.setStroke(width, color, dashWidth, dashGap);
 
@@ -218,13 +263,37 @@
         mStrokePaint.setPathEffect(e);
         invalidateSelf();
     }
-    
+
+
+    /**
+     * <p>Sets the size of the shape drawn by this drawable.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param width The width of the shape used by this drawable
+     * @param height The height of the shape used by this drawable
+     *
+     * @see #mutate()
+     * @see #setGradientType(int)
+     */
     public void setSize(int width, int height) {
         mGradientState.setSize(width, height);
         mPathIsDirty = true;
         invalidateSelf();
     }
-    
+
+    /**
+     * <p>Sets the type of shape used to draw the gradient.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param shape The desired shape for this drawable: {@link #LINE},
+     *              {@link #OVAL}, {@link #RECTANGLE} or {@link #RING}
+     *
+     * @see #mutate()
+     */
     public void setShape(int shape) {
         mRingPath = null;
         mPathIsDirty = true;
@@ -232,24 +301,73 @@
         invalidateSelf();
     }
 
+    /**
+     * <p>Sets the type of gradient used by this drawable..</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param gradient The type of the gradient: {@link #LINEAR_GRADIENT},
+     *                 {@link #RADIAL_GRADIENT} or {@link #SWEEP_GRADIENT}
+     *
+     * @see #mutate()
+     */
     public void setGradientType(int gradient) {
         mGradientState.setGradientType(gradient);
         mRectIsDirty = true;
         invalidateSelf();
     }
 
+    /**
+     * <p>Sets the center location of the gradient. The radius is honored only when 
+     * the gradient type is set to {@link #RADIAL_GRADIENT} or {@link #SWEEP_GRADIENT}.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param x The x coordinate of the gradient's center
+     * @param y The y coordinate of the gradient's center
+     *
+     * @see #mutate()
+     * @see #setGradientType(int)
+     */
     public void setGradientCenter(float x, float y) {
         mGradientState.setGradientCenter(x, y);
         mRectIsDirty = true;
         invalidateSelf();
     }
 
+    /**
+     * <p>Sets the radius of the gradient. The radius is honored only when the
+     * gradient type is set to {@link #RADIAL_GRADIENT}.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param gradientRadius The radius of the gradient in pixels
+     *
+     * @see #mutate()
+     * @see #setGradientType(int) 
+     */
     public void setGradientRadius(float gradientRadius) {
         mGradientState.setGradientRadius(gradientRadius);
         mRectIsDirty = true;
         invalidateSelf();
     }
 
+    /**
+     * <p>Sets whether or not this drawable will honor its <code>level</code>
+     * property.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param useLevel True if this drawable should honor its level, false otherwise
+     *
+     * @see #mutate()
+     * @see #setLevel(int) 
+     * @see #getLevel() 
+     */
     public void setUseLevel(boolean useLevel) {
         mGradientState.mUseLevel = useLevel;
         mRectIsDirty = true;
@@ -261,6 +379,47 @@
         return alpha * scale >> 8;
     }
 
+    /**
+     * Returns the orientation of the gradient defined in this drawable.
+     */
+    public Orientation getOrientation() {
+        return mGradientState.mOrientation;
+    }
+
+    /**
+     * <p>Changes the orientation of the gradient defined in this drawable.</p>
+     * <p><strong>Note</strong>: changing orientation will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing the orientation.</p>
+     * 
+     * @param orientation The desired orientation (angle) of the gradient
+     *                    
+     * @see #mutate() 
+     */
+    public void setOrientation(Orientation orientation) {
+        mGradientState.mOrientation = orientation;
+        mRectIsDirty = true;
+        invalidateSelf();
+    }
+
+    /**
+     * <p>Sets the colors used to draw the gradient. Each color is specified as an
+     * ARGB integer and the array must contain at least 2 colors.</p>
+     * <p><strong>Note</strong>: changing orientation will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing the orientation.</p>
+     *
+     * @param colors 2 or more ARGB colors
+     *
+     * @see #mutate()
+     * @see #setColor(int) 
+     */
+    public void setColors(int[] colors) {
+        mGradientState.setColors(colors);
+        mRectIsDirty = true;
+        invalidateSelf();
+    }
+
     @Override
     public void draw(Canvas canvas) {
         if (!ensureValidRect()) {
@@ -442,6 +601,17 @@
         return ringPath;
     }
 
+    /**
+     * <p>Changes this drawbale to use a single color instead of a gradient.</p>
+     * <p><strong>Note</strong>: changing orientation will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing the orientation.</p>
+     *
+     * @param argb The color used to fill the shape
+     *
+     * @see #mutate()
+     * @see #setColors(int[]) 
+     */
     public void setColor(int argb) {
         mGradientState.setSolidColor(argb);
         mFillPaint.setColor(argb);
@@ -450,10 +620,9 @@
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mGradientState.mChangingConfigurations;
+        return super.getChangingConfigurations() | mGradientState.mChangingConfigurations;
     }
-    
+
     @Override
     public void setAlpha(int alpha) {
         if (alpha != mAlpha) {
@@ -480,7 +649,6 @@
 
     @Override
     public int getOpacity() {
-        // XXX need to figure out the actual opacity...
         return PixelFormat.TRANSLUCENT;
     }
 
@@ -911,11 +1079,6 @@
         private float mGradientRadius = 0.5f;
         private boolean mUseLevel;
         private boolean mUseLevelForShape;
-        
-        
-        GradientState() {
-            mOrientation = Orientation.TOP_BOTTOM;
-        }
 
         GradientState(Orientation orientation, int[] colors) {
             mOrientation = orientation;
@@ -987,6 +1150,11 @@
             mCenterY = y;
         }
 
+        public void setColors(int[] colors) {
+            mHasSolidColor = false;
+            mColors = colors;
+        }
+        
         public void setSolidColor(int argb) {
             mHasSolidColor = true;
             mSolidColor = argb;
@@ -1055,4 +1223,3 @@
         }
     }
 }
-
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index f285f5b..44401c8 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2012 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.
@@ -22,6 +22,7 @@
 import android.content.res.AssetManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.SurfaceTexture;
 import android.util.Log;
 import android.util.TypedValue;
 
@@ -78,6 +79,8 @@
     boolean mConstrainedFace;
     boolean mConstrainedY;
     boolean mConstrainedZ;
+    boolean mReadAllowed = true;
+    boolean mWriteAllowed = true;
     int mSelectedY;
     int mSelectedZ;
     int mSelectedLOD;
@@ -127,6 +130,32 @@
      */
     public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010;
 
+    /**
+     * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allocation will be
+     * used with a SurfaceTexture object.  This usage will cause the
+     * allocation to be created read only.
+     *
+     * @hide
+     */
+    public static final int USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020;
+
+    /**
+     * USAGE_IO_INPUT The allocation will be
+     * used with a SurfaceTexture object.  This usage will cause the
+     * allocation to be created read only.
+     *
+     * @hide
+     */
+    public static final int USAGE_IO_INPUT = 0x0040;
+
+    /**
+     * USAGE_IO_OUTPUT The allocation will be
+     * used with a SurfaceTexture object.  This usage will cause the
+     * allocation to be created write only.
+     *
+     * @hide
+     */
+    public static final int USAGE_IO_OUTPUT = 0x0080;
 
     /**
      * Controls mipmap behavior when using the bitmap creation and
@@ -187,10 +216,26 @@
                        USAGE_GRAPHICS_TEXTURE |
                        USAGE_GRAPHICS_VERTEX |
                        USAGE_GRAPHICS_CONSTANTS |
-                       USAGE_GRAPHICS_RENDER_TARGET)) != 0) {
+                       USAGE_GRAPHICS_RENDER_TARGET |
+                       USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
+                       USAGE_IO_INPUT |
+                       USAGE_IO_OUTPUT)) != 0) {
             throw new RSIllegalArgumentException("Unknown usage specified.");
         }
+
+        if ((usage & (USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE | USAGE_IO_INPUT)) != 0) {
+            mWriteAllowed = false;
+
+            if ((usage & ~(USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE |
+                           USAGE_IO_INPUT |
+                           USAGE_GRAPHICS_TEXTURE |
+                           USAGE_SCRIPT)) != 0) {
+                throw new RSIllegalArgumentException("Invalid usage combination.");
+            }
+        }
+
         mType = t;
+        mUsage = usage;
 
         if (t != null) {
             updateCacheInfo(t);
@@ -487,6 +532,7 @@
 
         final byte[] data = fp.getData();
         int eSize = mType.mElement.mElements[component_number].getSizeBytes();
+        eSize *= mType.mElement.mArraySizes[component_number];
 
         if (data.length != eSize) {
             throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
@@ -875,7 +921,31 @@
         if (type.getID() == 0) {
             throw new RSInvalidStateException("Bad Type");
         }
-        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage);
+        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, 0);
+        if (id == 0) {
+            throw new RSRuntimeException("Allocation creation failed.");
+        }
+        return new Allocation(id, rs, type, usage);
+    }
+
+    /**
+     * @hide
+     * This API is hidden and only intended to be used for
+     * transitional purposes.
+     *
+     * @param type renderscript type describing data layout
+     * @param mips specifies desired mipmap behaviour for the
+     *             allocation
+     * @param usage bit field specifying how the allocation is
+     *              utilized
+     */
+    static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips,
+                                         int usage, int pointer) {
+        rs.validate();
+        if (type.getID() == 0) {
+            throw new RSInvalidStateException("Bad Type");
+        }
+        int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, pointer);
         if (id == 0) {
             throw new RSRuntimeException("Allocation creation failed.");
         }
@@ -930,7 +1000,7 @@
         b.setX(count);
         Type t = b.create();
 
-        int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage);
+        int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage, 0);
         if (id == 0) {
             throw new RSRuntimeException("Allocation creation failed.");
         }
@@ -1005,6 +1075,23 @@
     }
 
     /**
+     *
+     *
+     * @hide
+     *
+     */
+    public SurfaceTexture getSurfaceTexture() {
+        if ((mUsage & USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) == 0) {
+            throw new RSInvalidStateException("Allocation is not a surface texture.");
+        }
+
+        int id = mRS.nAllocationGetSurfaceTextureID(getID());
+        return new SurfaceTexture(id);
+
+    }
+
+
+    /**
      * Creates a non-mipmapped renderscript allocation to use as a
      * graphics texture
      *
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 22ef7bb..f6a0281 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -54,26 +54,59 @@
     int[] mArraySizes;
     int[] mOffsetInBytes;
 
+    int[] mVisibleElementMap;
+
     DataType mType;
     DataKind mKind;
     boolean mNormalized;
     int mVectorSize;
 
+    private void updateVisibleSubElements() {
+        if (mElements == null) {
+            return;
+        }
+
+        int noPaddingFieldCount = 0;
+        int fieldCount = mElementNames.length;
+        // Find out how many elements are not padding
+        for (int ct = 0; ct < fieldCount; ct ++) {
+            if (mElementNames[ct].charAt(0) != '#') {
+                noPaddingFieldCount ++;
+            }
+        }
+        mVisibleElementMap = new int[noPaddingFieldCount];
+
+        // Make a map that points us at non-padding elements
+        for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
+            if (mElementNames[ct].charAt(0) != '#') {
+                mVisibleElementMap[ctNoPadding ++] = ct;
+            }
+        }
+    }
+
     /**
     * @hide
     * @return element size in bytes
     */
     public int getSizeBytes() {return mSize;}
 
+    /**
+    * @hide
+    * @return element vector size
+    */
+    public int getVectorSize() {return mVectorSize;}
+
 
     /**
      * DataType represents the basic type information for a basic element.  The
-     * naming convention follows.  For numeric types its FLOAT, SIGNED, UNSIGNED
-     * followed by the _BITS where BITS is the size of the data.  BOOLEAN is a
-     * true / false (1,0) represented in an 8 bit container.  The UNSIGNED
-     * variants with multiple bit definitions are for packed graphical data
-     * formats and represents vectors with per vector member sizes which are
-     * treated as a single unit for packing and alignment purposes.
+     * naming convention follows.  For numeric types it is FLOAT,
+     * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+     * size of the data.  BOOLEAN is a true / false (1,0)
+     * represented in an 8 bit container.  The UNSIGNED variants
+     * with multiple bit definitions are for packed graphical data
+     * formats and represent vectors with per vector member sizes
+     * which are treated as a single unit for packing and alignment
+     * purposes.
      *
      * MATRIX the three matrix types contain FLOAT_32 elements and are treated
      * as 32 bits for alignment purposes.
@@ -81,6 +114,11 @@
      * RS_* objects.  32 bit opaque handles.
      */
     public enum DataType {
+        /**
+        * @hide
+        * new enum
+        */
+        NONE (0, 0),
         //FLOAT_16 (1, 2),
         FLOAT_32 (2, 4),
         FLOAT_64 (3, 8),
@@ -167,10 +205,10 @@
     * @return number of sub-elements in this element
     */
     public int getSubElementCount() {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             return 0;
         }
-        return mElements.length;
+        return mVisibleElementMap.length;
     }
 
     /**
@@ -179,13 +217,13 @@
     * @return sub-element in this element at given index
     */
     public Element getSubElement(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mElements[index];
+        return mElements[mVisibleElementMap[index]];
     }
 
     /**
@@ -194,13 +232,13 @@
     * @return sub-element in this element at given index
     */
     public String getSubElementName(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mElementNames[index];
+        return mElementNames[mVisibleElementMap[index]];
     }
 
     /**
@@ -209,13 +247,13 @@
     * @return array size of sub-element in this element at given index
     */
     public int getSubElementArraySize(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mArraySizes[index];
+        return mArraySizes[mVisibleElementMap[index]];
     }
 
     /**
@@ -224,13 +262,29 @@
     * @return offset in bytes of sub-element in this element at given index
     */
     public int getSubElementOffsetBytes(int index) {
-        if (mElements == null) {
+        if (mVisibleElementMap == null) {
             throw new RSIllegalArgumentException("Element contains no sub-elements");
         }
-        if (index < 0 || index >= mElements.length) {
+        if (index < 0 || index >= mVisibleElementMap.length) {
             throw new RSIllegalArgumentException("Illegal sub-element index");
         }
-        return mOffsetInBytes[index];
+        return mOffsetInBytes[mVisibleElementMap[index]];
+    }
+
+    /**
+    * @hide
+    * @return element data type
+    */
+    public DataType getDataType() {
+        return mType;
+    }
+
+    /**
+    * @hide
+    * @return element data kind
+    */
+    public DataKind getDataKind() {
+        return mKind;
     }
 
     /**
@@ -681,14 +735,18 @@
     Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
         super(id, rs);
         mSize = 0;
+        mVectorSize = 1;
         mElements = e;
         mElementNames = n;
         mArraySizes = as;
+        mType = DataType.NONE;
+        mKind = DataKind.USER;
         mOffsetInBytes = new int[mElements.length];
         for (int ct = 0; ct < mElements.length; ct++ ) {
             mOffsetInBytes[ct] = mSize;
             mSize += mElements[ct].mSize * mArraySizes[ct];
         }
+        updateVisibleSubElements();
     }
 
     Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -753,7 +811,7 @@
                 mSize += mElements[i].mSize * mArraySizes[i];
             }
         }
-
+        updateVisibleSubElements();
     }
 
     /**
diff --git a/graphics/java/android/renderscript/Path.java b/graphics/java/android/renderscript/Path.java
new file mode 100644
index 0000000..83ae150
--- /dev/null
+++ b/graphics/java/android/renderscript/Path.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.util.Vector;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ */
+public class Path extends BaseObj {
+
+    public enum Primitive {
+        QUADRATIC_BEZIER(0),
+        CUBIC_BEZIER(1);
+
+        int mID;
+        Primitive(int id) {
+            mID = id;
+        }
+    }
+
+    Allocation mVertexBuffer;
+    Allocation mLoopBuffer;
+    Primitive mPrimitive;
+    float mQuality;
+    boolean mCoverageToAlpha;
+
+    Path(int id, RenderScript rs, Primitive p, Allocation vtx, Allocation loop, float q) {
+        super(id, rs);
+        mVertexBuffer = vtx;
+        mLoopBuffer = loop;
+        mPrimitive = p;
+        mQuality = q;
+    }
+
+    public Allocation getVertexAllocation() {
+        return mVertexBuffer;
+    }
+
+    public Allocation getLoopAllocation() {
+        return mLoopBuffer;
+    }
+
+    public Primitive getPrimitive() {
+        return mPrimitive;
+    }
+
+    @Override
+    void updateFromNative() {
+    }
+
+
+    public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
+        int id = rs.nPathCreate(p.mID, false, vtx.getID(), 0, quality);
+        Path newPath = new Path(id, rs, p, null, null, quality);
+        return newPath;
+    }
+
+    public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
+        return null;
+    }
+
+    public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
+        return null;
+    }
+
+    public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
+        return null;
+    }
+
+
+}
+
+
diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java
index a1b1ba3..3f769ee 100644
--- a/graphics/java/android/renderscript/Program.java
+++ b/graphics/java/android/renderscript/Program.java
@@ -77,6 +77,40 @@
     }
 
     /**
+     * @hide
+     */
+    public int getConstantCount() {
+        return mConstants != null ? mConstants.length : 0;
+    }
+
+    /**
+     * @hide
+     */
+    public Type getConstant(int slot) {
+        if (slot < 0 || slot >= mConstants.length) {
+            throw new IllegalArgumentException("Slot ID out of range.");
+        }
+        return mConstants[slot];
+    }
+
+    /**
+     * @hide
+     */
+    public int getTextureCount() {
+        return mTextureCount;
+    }
+
+    /**
+     * @hide
+     */
+    public TextureType getTextureType(int slot) {
+        if ((slot < 0) || (slot >= mTextureCount)) {
+            throw new IllegalArgumentException("Slot ID out of range.");
+        }
+        return mTextures[slot];
+    }
+
+    /**
      * Binds a constant buffer to be used as uniform inputs to the
      * program
      *
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index 56bb836..b3c1bd9 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -55,6 +55,23 @@
     }
 
     /**
+     * @hide
+     */
+    public int getInputCount() {
+        return mInputs != null ? mInputs.length : 0;
+    }
+
+    /**
+     * @hide
+     */
+    public Element getInput(int slot) {
+        if (slot < 0 || slot >= mInputs.length) {
+            throw new IllegalArgumentException("Slot ID out of range.");
+        }
+        return mInputs[slot];
+    }
+
+    /**
     * Builder class for creating ProgramVertex objects.
     * The builder starts empty and the user must minimally provide
     * the GLSL shader code, and the varying inputs. Constant, or
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index ad10832..d3c801f2 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2012 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.
@@ -231,10 +231,10 @@
         rsnTypeGetNativeData(mContext, id, typeData);
     }
 
-    native int  rsnAllocationCreateTyped(int con, int type, int mip, int usage);
-    synchronized int nAllocationCreateTyped(int type, int mip, int usage) {
+    native int  rsnAllocationCreateTyped(int con, int type, int mip, int usage, int pointer);
+    synchronized int nAllocationCreateTyped(int type, int mip, int usage, int pointer) {
         validate();
-        return rsnAllocationCreateTyped(mContext, type, mip, usage);
+        return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
     }
     native int  rsnAllocationCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
     synchronized int nAllocationCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
@@ -269,6 +269,12 @@
         validate();
         rsnAllocationSyncAll(mContext, alloc, src);
     }
+    native int rsnAllocationGetSurfaceTextureID(int con, int alloc);
+    synchronized int nAllocationGetSurfaceTextureID(int alloc) {
+        validate();
+        return rsnAllocationGetSurfaceTextureID(mContext, alloc);
+    }
+
     native void rsnAllocationGenerateMipmaps(int con, int alloc);
     synchronized void nAllocationGenerateMipmaps(int alloc) {
         validate();
@@ -584,6 +590,11 @@
         rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
     }
 
+    native int  rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q);
+    synchronized int nPathCreate(int prim, boolean isStatic, int vtx, int loop, float q) {
+        validate();
+        return rsnPathCreate(mContext, prim, isStatic, vtx, loop, q);
+    }
 
     int     mDev;
     int     mContext;
@@ -837,7 +848,8 @@
                         mRS.mErrorCallback.mErrorNum = subID;
                         mRS.mErrorCallback.run();
                     } else {
-                        //throw new RSRuntimeException("Received error num " + subID + ", details: " + e);
+                        // Do not throw here. In these cases, we do not have
+                        // a fatal error.
                     }
                     continue;
                 }
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index bc1db4d..94f19b3 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -430,10 +430,10 @@
 // -----------------------------------
 
 static jint
-nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage)
+nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage, jint pointer)
 {
-    LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i)", con, (RsElement)type, mips, usage);
-    return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage);
+    LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", con, (RsElement)type, mips, usage, (void *)pointer);
+    return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer);
 }
 
 static void
@@ -443,6 +443,13 @@
     rsAllocationSyncAll(con, (RsAllocation)a, (RsAllocationUsageType)bits);
 }
 
+static jint
+nAllocationGetSurfaceTextureID(JNIEnv *_env, jobject _this, RsContext con, jint a)
+{
+    LOG_API("nAllocationGetSurfaceTextureID, con(%p), a(%p)", con, (RsAllocation)a);
+    return rsAllocationGetSurfaceTextureID(con, (RsAllocation)a);
+}
+
 static void
 nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, RsContext con, jint alloc)
 {
@@ -567,7 +574,7 @@
     jint len = _env->GetArrayLength(data);
     LOG_API("nAllocationElementData1D, con(%p), alloc(%p), offset(%i), comp(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, compIdx, len, sizeBytes);
     jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    rsAllocation1DElementData(con, (RsAllocation)alloc, offset, lod, ptr, compIdx, sizeBytes);
+    rsAllocation1DElementData(con, (RsAllocation)alloc, offset, lod, ptr, sizeBytes, compIdx);
     _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
 }
 
@@ -623,7 +630,7 @@
                         jint srcAlloc, jint srcXoff, jint srcYoff,
                         jint srcMip, jint srcFace)
 {
-    LOG_API("nAllocation2DData_s, con(%p), dstAlloc(%p), dstXoff, dstYoff,"
+    LOG_API("nAllocation2DData_s, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
             " dstMip(%i), dstFace(%i), width(%i), height(%i),"
             " srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i), srcFace(%i)",
             con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip, dstFace,
@@ -1122,6 +1129,17 @@
 
 // ---------------------------------------------------------------------------
 
+//native int  rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q);
+static jint
+nPathCreate(JNIEnv *_env, jobject _this, RsContext con, jint prim, jboolean isStatic, jint _vtx, jint _loop, jfloat q) {
+    LOG_API("nPathCreate, con(%p)", con);
+
+    int id = (int)rsPathCreate(con, (RsPathPrimitive)prim, isStatic,
+                               (RsAllocation)_vtx,
+                               (RsAllocation)_loop, q);
+    return id;
+}
+
 static jint
 nMeshCreate(JNIEnv *_env, jobject _this, RsContext con, jintArray _vtx, jintArray _idx, jintArray _prim)
 {
@@ -1250,7 +1268,7 @@
 {"rsnTypeCreate",                    "(IIIIIZZ)I",                            (void*)nTypeCreate },
 {"rsnTypeGetNativeData",             "(II[I)V",                               (void*)nTypeGetNativeData },
 
-{"rsnAllocationCreateTyped",         "(IIII)I",                               (void*)nAllocationCreateTyped },
+{"rsnAllocationCreateTyped",         "(IIIII)I",                               (void*)nAllocationCreateTyped },
 {"rsnAllocationCreateFromBitmap",    "(IIILandroid/graphics/Bitmap;I)I",      (void*)nAllocationCreateFromBitmap },
 {"rsnAllocationCubeCreateFromBitmap","(IIILandroid/graphics/Bitmap;I)I",      (void*)nAllocationCubeCreateFromBitmap },
 
@@ -1258,6 +1276,7 @@
 {"rsnAllocationCopyToBitmap",        "(IILandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyToBitmap },
 
 {"rsnAllocationSyncAll",             "(III)V",                                (void*)nAllocationSyncAll },
+{"rsnAllocationGetSurfaceTextureID", "(II)I",                                 (void*)nAllocationGetSurfaceTextureID },
 {"rsnAllocationData1D",              "(IIIII[II)V",                           (void*)nAllocationData1D_i },
 {"rsnAllocationData1D",              "(IIIII[SI)V",                           (void*)nAllocationData1D_s },
 {"rsnAllocationData1D",              "(IIIII[BI)V",                           (void*)nAllocationData1D_b },
@@ -1310,6 +1329,7 @@
 
 {"rsnSamplerCreate",                 "(IIIIIIF)I",                            (void*)nSamplerCreate },
 
+{"rsnPathCreate",                    "(IIZIIF)I",                             (void*)nPathCreate },
 {"rsnMeshCreate",                    "(I[I[I[I)I",                            (void*)nMeshCreate },
 
 {"rsnMeshGetVertexBufferCount",      "(II)I",                                 (void*)nMeshGetVertexBufferCount },
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index 990143b..93fcf69 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -114,8 +114,8 @@
 
     struct in_flight_event {
         android::InputEvent* event;
-        int seq;
-        bool doFinish;
+        int seq; // internal sequence number for synthetic pre-dispatch events
+        uint32_t finishSeq; // sequence number for sendFinishedSignal, or 0 if finish not required
     };
 
     struct finish_pre_dispatch {
diff --git a/include/binder/BinderService.h b/include/binder/BinderService.h
index 2316fef..ca594d3 100644
--- a/include/binder/BinderService.h
+++ b/include/binder/BinderService.h
@@ -34,15 +34,15 @@
 class BinderService
 {
 public:
-    static status_t publish() {
+    static status_t publish(bool allowIsolated = false) {
         sp<IServiceManager> sm(defaultServiceManager());
-        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
+        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
     }
 
-    static void publishAndJoinThreadPool() {
+    static void publishAndJoinThreadPool(bool allowIsolated = false) {
         sp<ProcessState> proc(ProcessState::self());
         sp<IServiceManager> sm(defaultServiceManager());
-        sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
+        sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);
         ProcessState::self()->startThreadPool();
         IPCThreadState::self()->joinThreadPool();
     }
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 3378d97..691ba2f 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -41,6 +41,7 @@
 
             int                 getCallingPid();
             int                 getCallingUid();
+            int                 getOrigCallingUid();
 
             void                setStrictModePolicy(int32_t policy);
             int32_t             getStrictModePolicy() const;
@@ -116,6 +117,7 @@
             status_t            mLastError;
             pid_t               mCallingPid;
             uid_t               mCallingUid;
+            uid_t               mOrigCallingUid;
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
 };
diff --git a/include/binder/IServiceManager.h b/include/binder/IServiceManager.h
index 24e9e99..2c297d6 100644
--- a/include/binder/IServiceManager.h
+++ b/include/binder/IServiceManager.h
@@ -47,7 +47,8 @@
      * Register a service.
      */
     virtual status_t            addService( const String16& name,
-                                            const sp<IBinder>& service) = 0;
+                                            const sp<IBinder>& service,
+                                            bool allowIsolated = false) = 0;
 
     /**
      * Return list of all existing services.
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
new file mode 100644
index 0000000..991a181
--- /dev/null
+++ b/include/gui/BufferQueue.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2012 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 ANDROID_GUI_BUFFERQUEUE_H
+#define ANDROID_GUI_BUFFERQUEUE_H
+
+#include <EGL/egl.h>
+
+#include <gui/ISurfaceTexture.h>
+
+#include <surfaceflinger/IGraphicBufferAlloc.h>
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class BufferQueue : public BnSurfaceTexture {
+public:
+    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
+    enum {
+        MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1,
+        MIN_SYNC_BUFFER_SLOTS  = MIN_UNDEQUEUED_BUFFERS
+    };
+    enum { NUM_BUFFER_SLOTS = 32 };
+    enum { NO_CONNECTED_API = 0 };
+
+    struct FrameAvailableListener : public virtual RefBase {
+        // onFrameAvailable() is called from queueBuffer() each time an
+        // additional frame becomes available for consumption. This means that
+        // frames that are queued while in asynchronous mode only trigger the
+        // callback if no previous frames are pending. Frames queued while in
+        // synchronous mode always trigger the callback.
+        //
+        // This is called without any lock held and can be called concurrently
+        // by multiple threads.
+        virtual void onFrameAvailable() = 0;
+    };
+
+    // BufferQueue manages a pool of gralloc memory slots to be used
+    // by producers and consumers.
+    // allowSynchronousMode specifies whether or not synchronous mode can be
+    // enabled.
+    BufferQueue(bool allowSynchronousMode = true);
+    virtual ~BufferQueue();
+
+    // setBufferCount updates the number of available buffer slots.  After
+    // calling this all buffer slots are both unallocated and owned by the
+    // BufferQueue object (i.e. they are not owned by the client).
+    virtual status_t setBufferCount(int bufferCount);
+
+    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
+
+    // dequeueBuffer gets the next buffer slot index for the client to use. If a
+    // buffer slot is available then that slot index is written to the location
+    // pointed to by the buf argument and a status of OK is returned.  If no
+    // slot is available then a status of -EBUSY is returned and buf is
+    // unmodified.
+    // The width and height parameters must be no greater than the minimum of
+    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+    // An error due to invalid dimensions might not be reported until
+    // updateTexImage() is called.
+    virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height,
+            uint32_t format, uint32_t usage);
+
+    // queueBuffer returns a filled buffer to the BufferQueue. In addition, a
+    // timestamp must be provided for the buffer. The timestamp is in
+    // nanoseconds, and must be monotonically increasing. Its other semantics
+    // (zero point, etc) are client-dependent and should be documented by the
+    // client.
+    virtual status_t queueBuffer(int buf, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+    virtual void cancelBuffer(int buf);
+    virtual status_t setCrop(const Rect& reg);
+    virtual status_t setTransform(uint32_t transform);
+    virtual status_t setScalingMode(int mode);
+
+    // setSynchronousMode set whether dequeueBuffer is synchronous or
+    // asynchronous. In synchronous mode, dequeueBuffer blocks until
+    // a buffer is available, the currently bound buffer can be dequeued and
+    // queued buffers will be retired in order.
+    // The default mode is asynchronous.
+    virtual status_t setSynchronousMode(bool enabled);
+
+    // connect attempts to connect a producer client API to the BufferQueue.
+    // This must be called before any other ISurfaceTexture methods are called
+    // except for getAllocator.
+    //
+    // This method will fail if the connect was previously called on the
+    // BufferQueue and no corresponding disconnect call was made.
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+
+    // disconnect attempts to disconnect a producer client API from the
+    // BufferQueue. Calling this method will cause any subsequent calls to other
+    // ISurfaceTexture methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the BufferQueue is not currently
+    // connected to the specified client API.
+    virtual status_t disconnect(int api);
+
+protected:
+
+    // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
+    // for the given slot.
+    void freeBufferLocked(int index);
+
+    // freeAllBuffersLocked frees the resources (both GraphicBuffer and
+    // EGLImage) for all slots.
+    void freeAllBuffersLocked();
+
+    // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer
+    // and EGLImage) for all slots except the head of mQueue
+    void freeAllBuffersExceptHeadLocked();
+
+    // drainQueueLocked drains the buffer queue if we're in synchronous mode
+    // returns immediately otherwise. It returns NO_INIT if the BufferQueue
+    // became abandoned or disconnected during this call.
+    status_t drainQueueLocked();
+
+    // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
+    // synchronous mode and free all buffers. In asynchronous mode, all buffers
+    // are freed except the current buffer.
+    status_t drainQueueAndFreeBuffersLocked();
+
+    status_t setBufferCountServerLocked(int bufferCount);
+
+    enum { INVALID_BUFFER_SLOT = -1 };
+
+    struct BufferSlot {
+
+        BufferSlot()
+        : mEglImage(EGL_NO_IMAGE_KHR),
+          mEglDisplay(EGL_NO_DISPLAY),
+          mBufferState(BufferSlot::FREE),
+          mRequestBufferCalled(false),
+          mTransform(0),
+          mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+          mTimestamp(0),
+          mFrameNumber(0),
+          mFence(EGL_NO_SYNC_KHR) {
+            mCrop.makeInvalid();
+        }
+
+        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+        // if no buffer has been allocated.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mEglImage is the EGLImage created from mGraphicBuffer.
+        EGLImageKHR mEglImage;
+
+        // mEglDisplay is the EGLDisplay used to create mEglImage.
+        EGLDisplay mEglDisplay;
+
+        // BufferState represents the different states in which a buffer slot
+        // can be.
+        enum BufferState {
+            // FREE indicates that the buffer is not currently being used and
+            // will not be used in the future until it gets dequeued and
+            // subsequently queued by the client.
+            FREE = 0,
+
+            // DEQUEUED indicates that the buffer has been dequeued by the
+            // client, but has not yet been queued or canceled. The buffer is
+            // considered 'owned' by the client, and the server should not use
+            // it for anything.
+            //
+            // Note that when in synchronous-mode (mSynchronousMode == true),
+            // the buffer that's currently attached to the texture may be
+            // dequeued by the client.  That means that the current buffer can
+            // be in either the DEQUEUED or QUEUED state.  In asynchronous mode,
+            // however, the current buffer is always in the QUEUED state.
+            DEQUEUED = 1,
+
+            // QUEUED indicates that the buffer has been queued by the client,
+            // and has not since been made available for the client to dequeue.
+            // Attaching the buffer to the texture does NOT transition the
+            // buffer away from the QUEUED state. However, in Synchronous mode
+            // the current buffer may be dequeued by the client under some
+            // circumstances. See the note about the current buffer in the
+            // documentation for DEQUEUED.
+            QUEUED = 2,
+        };
+
+        // mBufferState is the current state of this buffer slot.
+        BufferState mBufferState;
+
+        // mRequestBufferCalled is used for validating that the client did
+        // call requestBuffer() when told to do so. Technically this is not
+        // needed but useful for debugging and catching client bugs.
+        bool mRequestBufferCalled;
+
+        // mCrop is the current crop rectangle for this buffer slot. This gets
+        // set to mNextCrop each time queueBuffer gets called for this buffer.
+        Rect mCrop;
+
+        // mTransform is the current transform flags for this buffer slot. This
+        // gets set to mNextTransform each time queueBuffer gets called for this
+        // slot.
+        uint32_t mTransform;
+
+        // mScalingMode is the current scaling mode for this buffer slot. This
+        // gets set to mNextScalingMode each time queueBuffer gets called for
+        // this slot.
+        uint32_t mScalingMode;
+
+        // mTimestamp is the current timestamp for this buffer slot. This gets
+        // to set by queueBuffer each time this slot is queued.
+        int64_t mTimestamp;
+
+        // mFrameNumber is the number of the queued frame for this slot.
+        uint64_t mFrameNumber;
+
+        // mFence is the EGL sync object that must signal before the buffer
+        // associated with this buffer slot may be dequeued. It is initialized
+        // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
+        // on a compile-time option) set to a new sync object in updateTexImage.
+        EGLSyncKHR mFence;
+    };
+
+    // mSlots is the array of buffer slots that must be mirrored on the client
+    // side. This allows buffer ownership to be transferred between the client
+    // and server without sending a GraphicBuffer over binder. The entire array
+    // is initialized to NULL at construction time, and buffers are allocated
+    // for a slot when requestBuffer is called with that slot's index.
+    BufferSlot mSlots[NUM_BUFFER_SLOTS];
+
+
+    // mDefaultWidth holds the default width of allocated buffers. It is used
+    // in requestBuffers() if a width and height of zero is specified.
+    uint32_t mDefaultWidth;
+
+    // mDefaultHeight holds the default height of allocated buffers. It is used
+    // in requestBuffers() if a width and height of zero is specified.
+    uint32_t mDefaultHeight;
+
+    // mPixelFormat holds the pixel format of allocated buffers. It is used
+    // in requestBuffers() if a format of zero is specified.
+    uint32_t mPixelFormat;
+
+    // mBufferCount is the number of buffer slots that the client and server
+    // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
+    // by calling setBufferCount or setBufferCountServer
+    int mBufferCount;
+
+    // mClientBufferCount is the number of buffer slots requested by the client.
+    // The default is zero, which means the client doesn't care how many buffers
+    // there is.
+    int mClientBufferCount;
+
+    // mServerBufferCount buffer count requested by the server-side
+    int mServerBufferCount;
+
+    // mCurrentTexture is the buffer slot index of the buffer that is currently
+    // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
+    // indicating that no buffer slot is currently bound to the texture. Note,
+    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
+    // that no buffer is bound to the texture. A call to setBufferCount will
+    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
+    int mCurrentTexture;
+
+    // mNextCrop is the crop rectangle that will be used for the next buffer
+    // that gets queued. It is set by calling setCrop.
+    Rect mNextCrop;
+
+    // mNextTransform is the transform identifier that will be used for the next
+    // buffer that gets queued. It is set by calling setTransform.
+    uint32_t mNextTransform;
+
+    // mNextScalingMode is the scaling mode that will be used for the next
+    // buffers that get queued. It is set by calling setScalingMode.
+    int mNextScalingMode;
+
+    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
+    // allocate new GraphicBuffer objects.
+    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
+
+    // mFrameAvailableListener is the listener object that will be called when a
+    // new frame becomes available. If it is not NULL it will be called from
+    // queueBuffer.
+    sp<FrameAvailableListener> mFrameAvailableListener;
+
+    // mSynchronousMode whether we're in synchronous mode or not
+    bool mSynchronousMode;
+
+    // mAllowSynchronousMode whether we allow synchronous mode or not
+    const bool mAllowSynchronousMode;
+
+    // mConnectedApi indicates the API that is currently connected to this
+    // BufferQueue.  It defaults to NO_CONNECTED_API (= 0), and gets updated
+    // by the connect and disconnect methods.
+    int mConnectedApi;
+
+    // mDequeueCondition condition used for dequeueBuffer in synchronous mode
+    mutable Condition mDequeueCondition;
+
+    // mQueue is a FIFO of queued buffers used in synchronous mode
+    typedef Vector<int> Fifo;
+    Fifo mQueue;
+
+    // mAbandoned indicates that the BufferQueue will no longer be used to
+    // consume images buffers pushed to it using the ISurfaceTexture interface.
+    // It is initialized to false, and set to true in the abandon method.  A
+    // BufferQueue that has been abandoned will return the NO_INIT error from
+    // all ISurfaceTexture methods capable of returning an error.
+    bool mAbandoned;
+
+    // mName is a string used to identify the BufferQueue in log messages.
+    // It is set by the setName method.
+    String8 mName;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of BufferQueue objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+
+    // mFrameCounter is the free running counter, incremented for every buffer queued
+    // with the surface Texture.
+    uint64_t mFrameCounter;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_GUI_BUFFERQUEUE_H
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index dccc164..7bca8d6 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -63,7 +63,9 @@
 public:
     /*
      * DisplayEventReceiver creates and registers an event connection with
-     * SurfaceFlinger. Events start being delivered immediately.
+     * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate
+     * or requestNextVsync to receive them.
+     * Other events start being delivered immediately.
      */
     DisplayEventReceiver();
 
@@ -93,6 +95,8 @@
      * should be destroyed and getEvents() shouldn't be called again.
      */
     ssize_t getEvents(Event* events, size_t count);
+    static ssize_t getEvents(const sp<BitTube>& dataChannel,
+            Event* events, size_t count);
 
     /*
      * setVsyncRate() sets the Event::VSync delivery rate. A value of
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index a8c7672..4318f0f 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -23,6 +23,7 @@
 #include <GLES2/gl2ext.h>
 
 #include <gui/ISurfaceTexture.h>
+#include <gui/BufferQueue.h>
 
 #include <ui/GraphicBuffer.h>
 
@@ -35,30 +36,11 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-class IGraphicBufferAlloc;
+
 class String8;
 
-class SurfaceTexture : public BnSurfaceTexture {
+class SurfaceTexture : public BufferQueue {
 public:
-    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
-    enum {
-        MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1,
-        MIN_SYNC_BUFFER_SLOTS  = MIN_UNDEQUEUED_BUFFERS
-    };
-    enum { NUM_BUFFER_SLOTS = 32 };
-    enum { NO_CONNECTED_API = 0 };
-
-    struct FrameAvailableListener : public virtual RefBase {
-        // onFrameAvailable() is called from queueBuffer() each time an
-        // additional frame becomes available for consumption. This means that
-        // frames that are queued while in asynchronous mode only trigger the
-        // callback if no previous frames are pending. Frames queued while in
-        // synchronous mode always trigger the callback.
-        //
-        // This is called without any lock held and can be called concurrently
-        // by multiple threads.
-        virtual void onFrameAvailable() = 0;
-    };
 
     // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the
     // name of the OpenGL ES texture to which images are to be streamed. This
@@ -73,65 +55,8 @@
 
     virtual ~SurfaceTexture();
 
-    // setBufferCount updates the number of available buffer slots.  After
-    // calling this all buffer slots are both unallocated and owned by the
-    // SurfaceTexture object (i.e. they are not owned by the client).
-    virtual status_t setBufferCount(int bufferCount);
-
-    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
-
-    // dequeueBuffer gets the next buffer slot index for the client to use. If a
-    // buffer slot is available then that slot index is written to the location
-    // pointed to by the buf argument and a status of OK is returned.  If no
-    // slot is available then a status of -EBUSY is returned and buf is
-    // unmodified.
-    // The width and height parameters must be no greater than the minimum of
-    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
-    // An error due to invalid dimensions might not be reported until
-    // updateTexImage() is called.
-    virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height,
-            uint32_t format, uint32_t usage);
-
-    // queueBuffer returns a filled buffer to the SurfaceTexture. In addition, a
-    // timestamp must be provided for the buffer. The timestamp is in
-    // nanoseconds, and must be monotonically increasing. Its other semantics
-    // (zero point, etc) are client-dependent and should be documented by the
-    // client.
-    virtual status_t queueBuffer(int buf, int64_t timestamp,
-            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
-    virtual void cancelBuffer(int buf);
-    virtual status_t setCrop(const Rect& reg);
-    virtual status_t setTransform(uint32_t transform);
-    virtual status_t setScalingMode(int mode);
-
     virtual int query(int what, int* value);
 
-    // setSynchronousMode set whether dequeueBuffer is synchronous or
-    // asynchronous. In synchronous mode, dequeueBuffer blocks until
-    // a buffer is available, the currently bound buffer can be dequeued and
-    // queued buffers will be retired in order.
-    // The default mode is asynchronous.
-    virtual status_t setSynchronousMode(bool enabled);
-
-    // connect attempts to connect a client API to the SurfaceTexture.  This
-    // must be called before any other ISurfaceTexture methods are called except
-    // for getAllocator.
-    //
-    // This method will fail if the connect was previously called on the
-    // SurfaceTexture and no corresponding disconnect call was made.
-    virtual status_t connect(int api,
-            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
-
-    // disconnect attempts to disconnect a client API from the SurfaceTexture.
-    // Calling this method will cause any subsequent calls to other
-    // ISurfaceTexture methods to fail except for getAllocator and connect.
-    // Successfully calling connect after this will allow the other methods to
-    // succeed again.
-    //
-    // This method will fail if the the SurfaceTexture is not currently
-    // connected to the specified client API.
-    virtual status_t disconnect(int api);
-
     // updateTexImage sets the image contents of the target texture to that of
     // the most recently queued buffer.
     //
@@ -233,28 +158,6 @@
 
 protected:
 
-    // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
-    // for the given slot.
-    void freeBufferLocked(int index);
-
-    // freeAllBuffersLocked frees the resources (both GraphicBuffer and
-    // EGLImage) for all slots.
-    void freeAllBuffersLocked();
-
-    // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer
-    // and EGLImage) for all slots except the head of mQueue
-    void freeAllBuffersExceptHeadLocked();
-
-    // drainQueueLocked drains the buffer queue if we're in synchronous mode
-    // returns immediately otherwise. return NO_INIT if SurfaceTexture
-    // became abandoned or disconnected during this call.
-    status_t drainQueueLocked();
-
-    // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
-    // synchronous mode and free all buffers. In asynchronous mode, all buffers
-    // are freed except the current buffer.
-    status_t drainQueueAndFreeBuffersLocked();
-
     static bool isExternalFormat(uint32_t format);
 
 private:
@@ -263,146 +166,11 @@
     EGLImageKHR createImage(EGLDisplay dpy,
             const sp<GraphicBuffer>& graphicBuffer);
 
-    status_t setBufferCountServerLocked(int bufferCount);
-
     // computeCurrentTransformMatrix computes the transform matrix for the
     // current texture.  It uses mCurrentTransform and the current GraphicBuffer
     // to compute this matrix and stores it in mCurrentTransformMatrix.
     void computeCurrentTransformMatrix();
 
-    enum { INVALID_BUFFER_SLOT = -1 };
-
-    struct BufferSlot {
-
-        BufferSlot()
-            : mEglImage(EGL_NO_IMAGE_KHR),
-              mEglDisplay(EGL_NO_DISPLAY),
-              mBufferState(BufferSlot::FREE),
-              mRequestBufferCalled(false),
-              mTransform(0),
-              mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
-              mTimestamp(0),
-              mFrameNumber(0),
-              mFence(EGL_NO_SYNC_KHR) {
-            mCrop.makeInvalid();
-        }
-
-        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
-        // if no buffer has been allocated.
-        sp<GraphicBuffer> mGraphicBuffer;
-
-        // mEglImage is the EGLImage created from mGraphicBuffer.
-        EGLImageKHR mEglImage;
-
-        // mEglDisplay is the EGLDisplay used to create mEglImage.
-        EGLDisplay mEglDisplay;
-
-        // BufferState represents the different states in which a buffer slot
-        // can be.
-        enum BufferState {
-            // FREE indicates that the buffer is not currently being used and
-            // will not be used in the future until it gets dequeued and
-            // subsequently queued by the client.
-            FREE = 0,
-
-            // DEQUEUED indicates that the buffer has been dequeued by the
-            // client, but has not yet been queued or canceled. The buffer is
-            // considered 'owned' by the client, and the server should not use
-            // it for anything.
-            //
-            // Note that when in synchronous-mode (mSynchronousMode == true),
-            // the buffer that's currently attached to the texture may be
-            // dequeued by the client.  That means that the current buffer can
-            // be in either the DEQUEUED or QUEUED state.  In asynchronous mode,
-            // however, the current buffer is always in the QUEUED state.
-            DEQUEUED = 1,
-
-            // QUEUED indicates that the buffer has been queued by the client,
-            // and has not since been made available for the client to dequeue.
-            // Attaching the buffer to the texture does NOT transition the
-            // buffer away from the QUEUED state. However, in Synchronous mode
-            // the current buffer may be dequeued by the client under some
-            // circumstances. See the note about the current buffer in the
-            // documentation for DEQUEUED.
-            QUEUED = 2,
-        };
-
-        // mBufferState is the current state of this buffer slot.
-        BufferState mBufferState;
-
-        // mRequestBufferCalled is used for validating that the client did
-        // call requestBuffer() when told to do so. Technically this is not
-        // needed but useful for debugging and catching client bugs.
-        bool mRequestBufferCalled;
-
-        // mCrop is the current crop rectangle for this buffer slot. This gets
-        // set to mNextCrop each time queueBuffer gets called for this buffer.
-        Rect mCrop;
-
-        // mTransform is the current transform flags for this buffer slot. This
-        // gets set to mNextTransform each time queueBuffer gets called for this
-        // slot.
-        uint32_t mTransform;
-
-        // mScalingMode is the current scaling mode for this buffer slot. This
-        // gets set to mNextScalingMode each time queueBuffer gets called for
-        // this slot.
-        uint32_t mScalingMode;
-
-        // mTimestamp is the current timestamp for this buffer slot. This gets
-        // to set by queueBuffer each time this slot is queued.
-        int64_t mTimestamp;
-
-        // mFrameNumber is the number of the queued frame for this slot.
-        uint64_t mFrameNumber;
-
-        // mFence is the EGL sync object that must signal before the buffer
-        // associated with this buffer slot may be dequeued. It is initialized
-        // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
-        // on a compile-time option) set to a new sync object in updateTexImage.
-        EGLSyncKHR mFence;
-    };
-
-    // mSlots is the array of buffer slots that must be mirrored on the client
-    // side. This allows buffer ownership to be transferred between the client
-    // and server without sending a GraphicBuffer over binder. The entire array
-    // is initialized to NULL at construction time, and buffers are allocated
-    // for a slot when requestBuffer is called with that slot's index.
-    BufferSlot mSlots[NUM_BUFFER_SLOTS];
-
-    // mDefaultWidth holds the default width of allocated buffers. It is used
-    // in requestBuffers() if a width and height of zero is specified.
-    uint32_t mDefaultWidth;
-
-    // mDefaultHeight holds the default height of allocated buffers. It is used
-    // in requestBuffers() if a width and height of zero is specified.
-    uint32_t mDefaultHeight;
-
-    // mPixelFormat holds the pixel format of allocated buffers. It is used
-    // in requestBuffers() if a format of zero is specified.
-    uint32_t mPixelFormat;
-
-    // mBufferCount is the number of buffer slots that the client and server
-    // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
-    // by calling setBufferCount or setBufferCountServer
-    int mBufferCount;
-
-    // mClientBufferCount is the number of buffer slots requested by the client.
-    // The default is zero, which means the client doesn't care how many buffers
-    // there is.
-    int mClientBufferCount;
-
-    // mServerBufferCount buffer count requested by the server-side
-    int mServerBufferCount;
-
-    // mCurrentTexture is the buffer slot index of the buffer that is currently
-    // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
-    // indicating that no buffer slot is currently bound to the texture. Note,
-    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
-    // that no buffer is bound to the texture. A call to setBufferCount will
-    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
-    int mCurrentTexture;
-
     // mCurrentTextureBuf is the graphic buffer of the current texture. It's
     // possible that this buffer is not associated with any buffer slot, so we
     // must track it separately in order to support the getCurrentBuffer method.
@@ -429,72 +197,17 @@
     // gets set each time updateTexImage is called.
     int64_t mCurrentTimestamp;
 
-    // mNextCrop is the crop rectangle that will be used for the next buffer
-    // that gets queued. It is set by calling setCrop.
-    Rect mNextCrop;
-
-    // mNextTransform is the transform identifier that will be used for the next
-    // buffer that gets queued. It is set by calling setTransform.
-    uint32_t mNextTransform;
-
-    // mNextScalingMode is the scaling mode that will be used for the next
-    // buffers that get queued. It is set by calling setScalingMode.
-    int mNextScalingMode;
-
     // mTexName is the name of the OpenGL texture to which streamed images will
     // be bound when updateTexImage is called. It is set at construction time
     // changed with a call to setTexName.
     const GLuint mTexName;
 
-    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
-    // allocate new GraphicBuffer objects.
-    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
-
-    // mFrameAvailableListener is the listener object that will be called when a
-    // new frame becomes available. If it is not NULL it will be called from
-    // queueBuffer.
-    sp<FrameAvailableListener> mFrameAvailableListener;
-
-    // mSynchronousMode whether we're in synchronous mode or not
-    bool mSynchronousMode;
-
-    // mAllowSynchronousMode whether we allow synchronous mode or not
-    const bool mAllowSynchronousMode;
-
-    // mConnectedApi indicates the API that is currently connected to this
-    // SurfaceTexture.  It defaults to NO_CONNECTED_API (= 0), and gets updated
-    // by the connect and disconnect methods.
-    int mConnectedApi;
-
-    // mDequeueCondition condition used for dequeueBuffer in synchronous mode
-    mutable Condition mDequeueCondition;
-
-    // mQueue is a FIFO of queued buffers used in synchronous mode
-    typedef Vector<int> Fifo;
-    Fifo mQueue;
-
-    // mAbandoned indicates that the SurfaceTexture will no longer be used to
-    // consume images buffers pushed to it using the ISurfaceTexture interface.
-    // It is initialized to false, and set to true in the abandon method.  A
-    // SurfaceTexture that has been abandoned will return the NO_INIT error from
-    // all ISurfaceTexture methods capable of returning an error.
-    bool mAbandoned;
-
-    // mName is a string used to identify the SurfaceTexture in log messages.
-    // It is set by the setName method.
-    String8 mName;
-
     // mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync
     // extension should be used to prevent buffers from being dequeued before
     // it's safe for them to be written. It gets set at construction time and
     // never changes.
     const bool mUseFenceSync;
 
-    // mMutex is the mutex used to prevent concurrent access to the member
-    // variables of SurfaceTexture objects. It must be locked whenever the
-    // member variables are accessed.
-    mutable Mutex mMutex;
-
     // mTexTarget is the GL texture target with which the GL texture object is
     // associated.  It is set in the constructor and never changed.  It is
     // almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android
@@ -504,11 +217,6 @@
     // browser's tile cache exceeds.
     const GLenum mTexTarget;
 
-    // mFrameCounter is the free running counter, incremented for every buffer queued
-    // with the surface Texture.
-    uint64_t mFrameCounter;
-
-
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index 1417416..02dfc1b 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -108,7 +108,8 @@
      * Returned value
      *   *descriptor updated with effect descriptor
      */
-    static status_t getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor);
+    static status_t getEffectDescriptor(const effect_uuid_t *uuid,
+                                        effect_descriptor_t *descriptor) /*const*/;
 
 
     /*
@@ -226,8 +227,8 @@
     AudioEffect(const effect_uuid_t *type,
                 const effect_uuid_t *uuid = NULL,
                   int32_t priority = 0,
-                  effect_callback_t cbf = 0,
-                  void* user = 0,
+                  effect_callback_t cbf = NULL,
+                  void* user = NULL,
                   int sessionId = 0,
                   audio_io_handle_t io = 0
                   );
@@ -238,8 +239,8 @@
     AudioEffect(const char *typeStr,
                     const char *uuidStr = NULL,
                     int32_t priority = 0,
-                    effect_callback_t cbf = 0,
-                    void* user = 0,
+                    effect_callback_t cbf = NULL,
+                    void* user = NULL,
                     int sessionId = 0,
                     audio_io_handle_t io = 0
                     );
@@ -260,8 +261,8 @@
             status_t    set(const effect_uuid_t *type,
                             const effect_uuid_t *uuid = NULL,
                             int32_t priority = 0,
-                            effect_callback_t cbf = 0,
-                            void* user = 0,
+                            effect_callback_t cbf = NULL,
+                            void* user = NULL,
                             int sessionId = 0,
                             audio_io_handle_t io = 0
                             );
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 756e91d..437a89c 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -149,14 +149,14 @@
          RECORD_IIR_ENABLE = AUDIO_IN_ACOUSTICS_TX_IIR_ENABLE,
      };
 
-                        AudioRecord(int inputSource,
+                        AudioRecord(audio_source_t inputSource,
                                     uint32_t sampleRate = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                     uint32_t channelMask = AUDIO_CHANNEL_IN_MONO,
                                     int frameCount      = 0,
                                     uint32_t flags      = 0,
-                                    callback_t cbf = 0,
-                                    void* user = 0,
+                                    callback_t cbf = NULL,
+                                    void* user = NULL,
                                     int notificationFrames = 0,
                                     int sessionId = 0);
 
@@ -175,14 +175,14 @@
      *  - NO_INIT: audio server or audio hardware not initialized
      *  - PERMISSION_DENIED: recording is not allowed for the requesting process
      * */
-            status_t    set(int inputSource     = 0,
+            status_t    set(audio_source_t inputSource = AUDIO_SOURCE_DEFAULT,
                             uint32_t sampleRate = 0,
                             audio_format_t format = AUDIO_FORMAT_DEFAULT,
                             uint32_t channelMask = AUDIO_CHANNEL_IN_MONO,
                             int frameCount      = 0,
                             uint32_t flags      = 0,
-                            callback_t cbf = 0,
-                            void* user = 0,
+                            callback_t cbf = NULL,
+                            void* user = NULL,
                             int notificationFrames = 0,
                             bool threadCanCallJava = false,
                             int sessionId = 0);
@@ -208,7 +208,7 @@
             int         channels() const;
             uint32_t    frameCount() const;
             size_t      frameSize() const;
-            int         inputSource() const;
+            audio_source_t inputSource() const;
 
 
     /* After it's created the track is not active. Call start() to
@@ -341,10 +341,9 @@
     private:
         friend class AudioRecord;
         virtual bool        threadLoop();
-        virtual status_t    readyToRun() { return NO_ERROR; }
+        virtual status_t    readyToRun();
         virtual void        onFirstRef() {}
         AudioRecord& mReceiver;
-        Mutex       mLock;
     };
 
             bool processAudioBuffer(const sp<ClientRecordThread>& thread);
@@ -360,15 +359,16 @@
     sp<IAudioRecord>        mAudioRecord;
     sp<IMemory>             mCblkMemory;
     sp<ClientRecordThread>  mClientRecordThread;
+    status_t                mReadyToRun;
     Mutex                   mLock;
+    Condition               mCondition;
 
     uint32_t                mFrameCount;
 
     audio_track_cblk_t*     mCblk;
     audio_format_t          mFormat;
     uint8_t                 mChannelCount;
-    uint8_t                 mInputSource;
-    uint8_t                 mReserved[2];
+    audio_source_t          mInputSource;
     status_t                mStatus;
     uint32_t                mLatency;
 
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index c6368fb..1916ac5 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -55,8 +55,10 @@
     static status_t getMasterMute(bool* mute);
 
     // set/get stream volume on specified output
-    static status_t setStreamVolume(audio_stream_type_t stream, float value, int output);
-    static status_t getStreamVolume(audio_stream_type_t stream, float* volume, int output);
+    static status_t setStreamVolume(audio_stream_type_t stream, float value,
+                                    audio_io_handle_t output);
+    static status_t getStreamVolume(audio_stream_type_t stream, float* volume,
+                                    audio_io_handle_t output);
 
     // mute/unmute stream
     static status_t setStreamMute(audio_stream_type_t stream, bool mute);
@@ -129,7 +131,7 @@
         NUM_CONFIG_EVENTS
     };
 
-    // audio output descritor used to cache output configurations in client process to avoid frequent calls
+    // audio output descriptor used to cache output configurations in client process to avoid frequent calls
     // through IAudioFlinger
     class OutputDescriptor {
     public:
@@ -163,7 +165,7 @@
                                audio_stream_type_t stream,
                                int session = 0);
     static void releaseOutput(audio_io_handle_t output);
-    static audio_io_handle_t getInput(int inputSource,
+    static audio_io_handle_t getInput(audio_source_t inputSource,
                                     uint32_t samplingRate = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                     uint32_t channels = AUDIO_CHANNEL_IN_MONO,
@@ -217,7 +219,7 @@
 
         // indicate a change in the configuration of an output or input: keeps the cached
         // values for output/input parameters upto date in client process
-        virtual void ioConfigChanged(int event, int ioHandle, void *param2);
+        virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, void *param2);
     };
 
     class AudioPolicyServiceClient: public IBinder::DeathRecipient
@@ -248,7 +250,7 @@
     static sp<IAudioPolicyService> gAudioPolicyService;
 
     // mapping between stream types and outputs
-    static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap;
+    static DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> gStreamOutputMap;
     // list of output descriptors containing cached parameters
     // (sampling rate, framecount, channel count...)
     static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 98abfbd..ac7f6cf 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -58,8 +58,8 @@
         EVENT_BUFFER_END = 5        // Playback head is at the end of the buffer.
     };
 
-    /* Create Buffer on the stack and pass it to obtainBuffer()
-     * and releaseBuffer().
+    /* Client should declare Buffer on the stack and pass address to obtainBuffer()
+     * and releaseBuffer().  See also callback_t for EVENT_MORE_DATA.
      */
 
     class Buffer
@@ -68,12 +68,16 @@
         enum {
             MUTE    = 0x00000001
         };
-        uint32_t    flags;
+        uint32_t    flags;        // 0 or MUTE
         audio_format_t format; // but AUDIO_FORMAT_PCM_8_BIT -> AUDIO_FORMAT_PCM_16_BIT
         // accessed directly by WebKit ANP callback
         int         channelCount; // will be removed in the future, do not use
-        size_t      frameCount;
-        size_t      size;
+
+        size_t      frameCount;   // number of sample frames corresponding to size;
+                                  // on input it is the number of frames desired,
+                                  // on output is the number of frames actually filled
+
+        size_t      size;         // input/output in byte units
         union {
             void*       raw;
             short*      i16;    // signed 16-bit
@@ -84,15 +88,15 @@
 
     /* As a convenience, if a callback is supplied, a handler thread
      * is automatically created with the appropriate priority. This thread
-     * invokes the callback when a new buffer becomes available or an underrun condition occurs.
+     * invokes the callback when a new buffer becomes available or various conditions occur.
      * Parameters:
      *
      * event:   type of event notified (see enum AudioTrack::event_type).
      * user:    Pointer to context for use by the callback receiver.
      * info:    Pointer to optional parameter according to event type:
      *          - EVENT_MORE_DATA: pointer to AudioTrack::Buffer struct. The callback must not write
-     *          more bytes than indicated by 'size' field and update 'size' if less bytes are
-     *          written.
+     *            more bytes than indicated by 'size' field and update 'size' if fewer bytes are
+     *            written.
      *          - EVENT_UNDERRUN: unused.
      *          - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining.
      *          - EVENT_MARKER: pointer to an uint32_t containing the marker position in frames.
@@ -148,8 +152,8 @@
                                     int channelMask      = 0,
                                     int frameCount       = 0,
                                     uint32_t flags       = 0,
-                                    callback_t cbf       = 0,
-                                    void* user           = 0,
+                                    callback_t cbf       = NULL,
+                                    void* user           = NULL,
                                     int notificationFrames = 0,
                                     int sessionId = 0);
 
@@ -180,8 +184,8 @@
                                     int channelMask     = 0,
                                     const sp<IMemory>& sharedBuffer = 0,
                                     uint32_t flags      = 0,
-                                    callback_t cbf      = 0,
-                                    void* user          = 0,
+                                    callback_t cbf      = NULL,
+                                    void* user          = NULL,
                                     int notificationFrames = 0,
                                     int sessionId = 0);
 
@@ -204,8 +208,8 @@
                             int channelMask     = 0,
                             int frameCount      = 0,
                             uint32_t flags      = 0,
-                            callback_t cbf      = 0,
-                            void* user          = 0,
+                            callback_t cbf      = NULL,
+                            void* user          = NULL,
                             int notificationFrames = 0,
                             const sp<IMemory>& sharedBuffer = 0,
                             bool threadCanCallJava = false,
@@ -225,7 +229,7 @@
      */
             uint32_t     latency() const;
 
-    /* getters, see constructor */
+    /* getters, see constructors and set() */
 
             audio_stream_type_t streamType() const;
             audio_format_t format() const;
@@ -273,18 +277,18 @@
      * left and right volumes. Levels must be >= 0.0 and <= 1.0.
      */
             status_t    setVolume(float left, float right);
-            void        getVolume(float* left, float* right);
+            void        getVolume(float* left, float* right) const;
 
     /* Set the send level for this track. An auxiliary effect should be attached
      * to the track with attachEffect(). Level must be >= 0.0 and <= 1.0.
      */
             status_t    setAuxEffectSendLevel(float level);
-            void        getAuxEffectSendLevel(float* level);
+            void        getAuxEffectSendLevel(float* level) const;
 
     /* Set sample rate for this track, mostly used for games' sound effects
      */
             status_t    setSampleRate(int sampleRate);
-            uint32_t    getSampleRate();
+            uint32_t    getSampleRate() const;
 
     /* Enables looping and sets the start and end points of looping.
      *
@@ -299,7 +303,6 @@
      *          (loopEnd-loopStart) <= framecount()
      */
             status_t    setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
-            status_t    getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount);
 
     /* Sets marker position. When playback reaches the number of frames specified, a callback with
      * event type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker
@@ -315,7 +318,7 @@
      *  - INVALID_OPERATION: the AudioTrack has no callback installed.
      */
             status_t    setMarkerPosition(uint32_t marker);
-            status_t    getMarkerPosition(uint32_t *marker);
+            status_t    getMarkerPosition(uint32_t *marker) const;
 
 
     /* Sets position update period. Every time the number of frames specified has been played,
@@ -333,7 +336,7 @@
      *  - INVALID_OPERATION: the AudioTrack has no callback installed.
      */
             status_t    setPositionUpdatePeriod(uint32_t updatePeriod);
-            status_t    getPositionUpdatePeriod(uint32_t *updatePeriod);
+            status_t    getPositionUpdatePeriod(uint32_t *updatePeriod) const;
 
     /* Sets playback head position within AudioTrack buffer. The new position is specified
      * in number of frames.
@@ -384,7 +387,7 @@
      * Returned value:
      *  AudioTrack session ID.
      */
-            int    getSessionId();
+            int    getSessionId() const;
 
     /* Attach track auxiliary output to specified effect. Use effectId = 0
      * to detach track from effect.
@@ -401,13 +404,19 @@
             status_t    attachAuxEffect(int effectId);
 
     /* Obtains a buffer of "frameCount" frames. The buffer must be
-     * filled entirely. If the track is stopped, obtainBuffer() returns
+     * filled entirely, and then released with releaseBuffer().
+     * If the track is stopped, obtainBuffer() returns
      * STOPPED instead of NO_ERROR as long as there are buffers available,
      * at which point NO_MORE_BUFFERS is returned.
      * Buffers will be returned until the pool (buffercount())
      * is exhausted, at which point obtainBuffer() will either block
      * or return WOULD_BLOCK depending on the value of the "blocking"
      * parameter.
+     *
+     * Interpretation of waitCount:
+     *  +n  limits wait time to n * WAIT_PERIOD_MS,
+     *  -1  causes an (almost) infinite wait time,
+     *   0  non-blocking.
      */
 
         enum {
@@ -416,12 +425,19 @@
         };
 
             status_t    obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
+
+    /* Release a filled buffer of "frameCount" frames for AudioFlinger to process. */
             void        releaseBuffer(Buffer* audioBuffer);
 
     /* As a convenience we provide a write() interface to the audio buffer.
-     * This is implemented on top of lockBuffer/unlockBuffer. For best
-     * performance use callbacks. Return actual number of bytes written.
-     *
+     * This is implemented on top of obtainBuffer/releaseBuffer. For best
+     * performance use callbacks. Returns actual number of bytes written >= 0,
+     * or one of the following negative status codes:
+     *      INVALID_OPERATION   AudioTrack is configured for shared buffer mode
+     *      BAD_VALUE           size is invalid
+     *      STOPPED             AudioTrack was stopped during the write
+     *      NO_MORE_BUFFERS     when obtainBuffer() returns same
+     *      or any other error code returned by IAudioTrack::start() or restoreTrack_l().
      */
             ssize_t     write(const void* buffer, size_t size);
 
@@ -446,9 +462,9 @@
         virtual status_t    readyToRun();
         virtual void        onFirstRef();
         AudioTrack& mReceiver;
-        Mutex       mLock;
     };
 
+            // body of AudioTrackThread::threadLoop()
             bool processAudioBuffer(const sp<AudioTrackThread>& thread);
             status_t createTrack_l(audio_stream_type_t streamType,
                                  uint32_t sampleRate,
@@ -485,7 +501,7 @@
 
     bool                    mActive;                // protected by mLock
 
-    callback_t              mCbf;
+    callback_t              mCbf;                   // callback handler for events, or NULL
     void*                   mUserData;
     uint32_t                mNotificationFramesReq; // requested number of frames between each notification callback
     uint32_t                mNotificationFramesAct; // actual number of frames between each notification callback
diff --git a/include/media/EffectsFactoryApi.h b/include/media/EffectsFactoryApi.h
index 8ae13cc..65c26f47 100644
--- a/include/media/EffectsFactoryApi.h
+++ b/include/media/EffectsFactoryApi.h
@@ -87,7 +87,7 @@
 //    Description:    Creates an effect engine of the specified type and returns an
 //          effect control interface on this engine. The function will allocate the
 //          resources for an instance of the requested effect engine and return
-//          a handler on the effect control interface.
+//          a handle on the effect control interface.
 //
 //    Input:
 //          pEffectUuid:    pointer to the effect uuid.
@@ -109,23 +109,23 @@
 //        *pHandle:         updated with the effect handle.
 //
 ////////////////////////////////////////////////////////////////////////////////
-int EffectCreate(effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle);
+int EffectCreate(const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle);
 
 ////////////////////////////////////////////////////////////////////////////////
 //
 //    Function:       EffectRelease
 //
-//    Description:    Releases the effect engine whose handler is given as argument.
+//    Description:    Releases the effect engine whose handle is given as argument.
 //          All resources allocated to this particular instance of the effect are
 //          released.
 //
 //    Input:
-//          handle:    handler on the effect interface to be released.
+//          handle:    handle on the effect interface to be released.
 //
 //    Output:
 //        returned value:    0          successful operation.
 //                          -ENODEV     factory failed to initialize
-//                          -EINVAL     invalid interface handler
+//                          -EINVAL     invalid interface handle
 //
 ////////////////////////////////////////////////////////////////////////////////
 int EffectRelease(effect_handle_t handle);
@@ -151,7 +151,7 @@
 //        *pDescriptor:     updated with the effect descriptor.
 //
 ////////////////////////////////////////////////////////////////////////////////
-int EffectGetDescriptor(effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor);
+int EffectGetDescriptor(const effect_uuid_t *pEffectUuid, effect_descriptor_t *pDescriptor);
 
 ////////////////////////////////////////////////////////////////////////////////
 //
@@ -167,7 +167,7 @@
 //                           1 if uuid is equal to EFFECT_UUID_NULL.
 //
 ////////////////////////////////////////////////////////////////////////////////
-int EffectIsNullUuid(effect_uuid_t *pEffectUuid);
+int EffectIsNullUuid(const effect_uuid_t *pEffectUuid);
 
 #if __cplusplus
 }  // extern "C"
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 7c0d886..433ce7c 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -27,6 +27,7 @@
 #include <media/IAudioTrack.h>
 #include <media/IAudioRecord.h>
 #include <media/IAudioFlingerClient.h>
+#include <system/audio.h>
 #include <hardware/audio_effect.h>
 #include <media/IEffect.h>
 #include <media/IEffectClient.h>
@@ -53,13 +54,13 @@
                                 int frameCount,
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
-                                int output,
+                                audio_io_handle_t output,
                                 int *sessionId,
                                 status_t *status) = 0;
 
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
-                                int input,
+                                audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 uint32_t channelMask,
@@ -71,11 +72,11 @@
     /* query the audio hardware state. This state never changes,
      * and therefore can be cached.
      */
-    virtual     uint32_t    sampleRate(int output) const = 0;
-    virtual     int         channelCount(int output) const = 0;
-    virtual     audio_format_t format(int output) const = 0;
-    virtual     size_t      frameCount(int output) const = 0;
-    virtual     uint32_t    latency(int output) const = 0;
+    virtual     uint32_t    sampleRate(audio_io_handle_t output) const = 0;
+    virtual     int         channelCount(audio_io_handle_t output) const = 0;
+    virtual     audio_format_t format(audio_io_handle_t output) const = 0;
+    virtual     size_t      frameCount(audio_io_handle_t output) const = 0;
+    virtual     uint32_t    latency(audio_io_handle_t output) const = 0;
 
     /* set/get the audio hardware state. This will probably be used by
      * the preference panel, mostly.
@@ -89,10 +90,12 @@
     /* set/get stream type state. This will probably be used by
      * the preference panel, mostly.
      */
-    virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value, int output) = 0;
+    virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value,
+                                    audio_io_handle_t output) = 0;
     virtual     status_t    setStreamMute(audio_stream_type_t stream, bool muted) = 0;
 
-    virtual     float       streamVolume(audio_stream_type_t stream, int output) const = 0;
+    virtual     float       streamVolume(audio_stream_type_t stream,
+                                    audio_io_handle_t output) const = 0;
     virtual     bool        streamMute(audio_stream_type_t stream) const = 0;
 
     // set audio mode
@@ -102,63 +105,68 @@
     virtual     status_t    setMicMute(bool state) = 0;
     virtual     bool        getMicMute() const = 0;
 
-    virtual     status_t    setParameters(int ioHandle, const String8& keyValuePairs) = 0;
-    virtual     String8     getParameters(int ioHandle, const String8& keys) = 0;
+    virtual     status_t    setParameters(audio_io_handle_t ioHandle,
+                                    const String8& keyValuePairs) = 0;
+    virtual     String8     getParameters(audio_io_handle_t ioHandle, const String8& keys) const = 0;
 
     // register a current process for audio output change notifications
     virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
 
     // retrieve the audio recording buffer size
-    virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) = 0;
+    virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const = 0;
 
-    virtual int openOutput(uint32_t *pDevices,
+    virtual audio_io_handle_t openOutput(uint32_t *pDevices,
                                     uint32_t *pSamplingRate,
                                     audio_format_t *pFormat,
                                     uint32_t *pChannels,
                                     uint32_t *pLatencyMs,
                                     uint32_t flags) = 0;
-    virtual int openDuplicateOutput(int output1, int output2) = 0;
-    virtual status_t closeOutput(int output) = 0;
-    virtual status_t suspendOutput(int output) = 0;
-    virtual status_t restoreOutput(int output) = 0;
+    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+                                    audio_io_handle_t output2) = 0;
+    virtual status_t closeOutput(audio_io_handle_t output) = 0;
+    virtual status_t suspendOutput(audio_io_handle_t output) = 0;
+    virtual status_t restoreOutput(audio_io_handle_t output) = 0;
 
-    virtual int openInput(uint32_t *pDevices,
+    virtual audio_io_handle_t openInput(uint32_t *pDevices,
                                     uint32_t *pSamplingRate,
                                     audio_format_t *pFormat,
                                     uint32_t *pChannels,
-                                    uint32_t acoustics) = 0;
-    virtual status_t closeInput(int input) = 0;
+                                    audio_in_acoustics_t acoustics) = 0;
+    virtual status_t closeInput(audio_io_handle_t input) = 0;
 
-    virtual status_t setStreamOutput(audio_stream_type_t stream, int output) = 0;
+    virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output) = 0;
 
     virtual status_t setVoiceVolume(float volume) = 0;
 
-    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) = 0;
+    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
+                                    audio_io_handle_t output) const = 0;
 
-    virtual unsigned int  getInputFramesLost(int ioHandle) = 0;
+    virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const = 0;
 
     virtual int newAudioSessionId() = 0;
 
     virtual void acquireAudioSessionId(int audioSession) = 0;
     virtual void releaseAudioSessionId(int audioSession) = 0;
 
-    virtual status_t queryNumberEffects(uint32_t *numEffects) = 0;
+    virtual status_t queryNumberEffects(uint32_t *numEffects) const = 0;
 
-    virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) = 0;
+    virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) const = 0;
 
-    virtual status_t getEffectDescriptor(effect_uuid_t *pEffectUUID, effect_descriptor_t *pDescriptor) = 0;
+    virtual status_t getEffectDescriptor(const effect_uuid_t *pEffectUUID,
+                                        effect_descriptor_t *pDescriptor) const = 0;
 
     virtual sp<IEffect> createEffect(pid_t pid,
                                     effect_descriptor_t *pDesc,
                                     const sp<IEffectClient>& client,
                                     int32_t priority,
-                                    int output,
+                                    audio_io_handle_t output,
                                     int sessionId,
                                     status_t *status,
                                     int *id,
                                     int *enabled) = 0;
 
-    virtual status_t moveEffects(int session, int srcOutput, int dstOutput) = 0;
+    virtual status_t moveEffects(int session, audio_io_handle_t srcOutput,
+                                    audio_io_handle_t dstOutput) = 0;
 };
 
 
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
index aa0cdcf..f3b4df1 100644
--- a/include/media/IAudioFlingerClient.h
+++ b/include/media/IAudioFlingerClient.h
@@ -21,6 +21,7 @@
 #include <utils/RefBase.h>
 #include <binder/IInterface.h>
 #include <utils/KeyedVector.h>
+#include <system/audio.h>
 
 namespace android {
 
@@ -32,7 +33,7 @@
     DECLARE_META_INTERFACE(AudioFlingerClient);
 
     // Notifies a change of audio input/output configuration.
-    virtual void ioConfigChanged(int event, int ioHandle, void *param2) = 0;
+    virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, void *param2) = 0;
 
 };
 
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 07d17c5..4d88297 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -60,7 +60,7 @@
                                 audio_stream_type_t stream,
                                 int session = 0) = 0;
     virtual void releaseOutput(audio_io_handle_t output) = 0;
-    virtual audio_io_handle_t getInput(int inputSource,
+    virtual audio_io_handle_t getInput(audio_source_t inputSource,
                                     uint32_t samplingRate = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                     uint32_t channels = 0,
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index 46735de..7869020 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -37,8 +37,9 @@
 
     /* After it's created the track is not active. Call start() to
      * make it active. If set, the callback will start being called.
+     * tid identifies the client callback thread, or 0 if not needed.
      */
-    virtual status_t    start() = 0;
+    virtual status_t    start(pid_t tid) = 0;
 
     /* Stop a track. If set, the callback will cease being called and
      * obtainBuffer will return an error. Buffers that are already released 
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index b83e552..e4772a1 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -40,17 +40,18 @@
 
     /* After it's created the track is not active. Call start() to
      * make it active. If set, the callback will start being called.
+     * tid identifies the client callback thread, or 0 if not needed.
      */
-    virtual status_t    start() = 0;
+    virtual status_t    start(pid_t tid) = 0;
 
     /* Stop a track. If set, the callback will cease being called and
      * obtainBuffer will return an error. Buffers that are already released 
-     * will be processed, unless flush() is called.
+     * will continue to be processed, unless/until flush() is called.
      */
     virtual void        stop() = 0;
 
-    /* Flush a stopped track. All pending buffers are discarded.
-     * This function has no effect if the track is not stopped.
+    /* Flush a stopped or paused track. All pending/released buffers are discarded.
+     * This function has no effect if the track is not stopped or paused.
      */
     virtual void        flush() = 0;
 
@@ -61,7 +62,7 @@
     
     /* Pause a track. If set, the callback will cease being called and
      * obtainBuffer will return an error. Buffers that are already released 
-     * will be processed, unless flush() is called.
+     * will continue to be processed, unless/until flush() is called.
      */
     virtual void        pause() = 0;
 
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index c4cc947..a295e9a 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -42,10 +42,10 @@
     typedef void *buffer_id;
     typedef void *node_id;
 
-    // Given the calling process' pid, returns true iff
+    // Given a node_id and the calling process' pid, returns true iff
     // the implementation of the OMX interface lives in the same
     // process.
-    virtual bool livesLocally(pid_t pid) = 0;
+    virtual bool livesLocally(node_id node, pid_t pid) = 0;
 
     struct ComponentInfo {
         String8 mName;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 7beb176..77c82b2 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -96,6 +96,8 @@
         virtual void        flush() = 0;
         virtual void        pause() = 0;
         virtual void        close() = 0;
+
+        virtual status_t    setPlaybackRatePermille(int32_t rate) { return INVALID_OPERATION; }
     };
 
                         MediaPlayerBase() : mCookie(0), mNotify(0) {}
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
index 290b748..ac0f6b2 100644
--- a/include/media/MemoryLeakTrackUtil.h
+++ b/include/media/MemoryLeakTrackUtil.h
@@ -19,7 +19,7 @@
 
 namespace android {
 /*
- * Dump the memory adddress of the calling process to the given fd.
+ * Dump the memory address of the calling process to the given fd.
  */
 extern void dumpMemoryAddresses(int fd);
 
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index 7d890bd..df0c97e 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -154,7 +154,7 @@
     ToneGenerator(audio_stream_type_t streamType, float volume, bool threadCanCallJava = false);
     ~ToneGenerator();
 
-    bool startTone(int toneType, int durationMs = -1);
+    bool startTone(tone_type toneType, int durationMs = -1);
     void stopTone();
 
     bool isInited() { return (mState == TONE_IDLE)?false:true;}
@@ -274,7 +274,7 @@
     bool prepareWave();
     unsigned int numWaves(unsigned int segmentIdx);
     void clearWaveGens();
-    int getToneForRegion(int toneType);
+    tone_type getToneForRegion(tone_type toneType);
 
     // WaveGenerator generates a single sine wave
     class WaveGenerator {
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
index 1a4cbca..60fa15b 100644
--- a/include/media/Visualizer.h
+++ b/include/media/Visualizer.h
@@ -66,8 +66,8 @@
      * See AudioEffect constructor for details on parameters.
      */
                         Visualizer(int32_t priority = 0,
-                                   effect_callback_t cbf = 0,
-                                   void* user = 0,
+                                   effect_callback_t cbf = NULL,
+                                   void* user = NULL,
                                    int sessionId = 0);
 
                         ~Visualizer();
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 00b7dd5..d0b87c8 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -145,6 +145,9 @@
     // audio track, or zero for error (e.g. no audio track) or unknown.
     KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200,                   // get only
 
+    // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
+    // values used for rewinding or reverse playback.
+    KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300,                // set only
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h
index fa3ab8a..49397ee 100644
--- a/include/media/stagefright/AACWriter.h
+++ b/include/media/stagefright/AACWriter.h
@@ -34,7 +34,7 @@
     virtual status_t addSource(const sp<MediaSource> &source);
     virtual bool reachedEOS();
     virtual status_t start(MetaData *params = NULL);
-    virtual status_t stop();
+    virtual status_t stop() { return reset(); }
     virtual status_t pause();
 
 protected:
@@ -66,6 +66,7 @@
     bool exceedsFileSizeLimit();
     bool exceedsFileDurationLimit();
     status_t writeAdtsHeader(uint32_t frameLength);
+    status_t reset();
 
     DISALLOW_EVIL_CONSTRUCTORS(AACWriter);
 };
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h
index 62d57b4..392f968 100644
--- a/include/media/stagefright/AMRWriter.h
+++ b/include/media/stagefright/AMRWriter.h
@@ -37,7 +37,7 @@
     virtual status_t addSource(const sp<MediaSource> &source);
     virtual bool reachedEOS();
     virtual status_t start(MetaData *params = NULL);
-    virtual status_t stop();
+    virtual status_t stop() { return reset(); }
     virtual status_t pause();
 
 protected:
@@ -60,6 +60,7 @@
     status_t threadFunc();
     bool exceedsFileSizeLimit();
     bool exceedsFileDurationLimit();
+    status_t reset();
 
     AMRWriter(const AMRWriter &);
     AMRWriter &operator=(const AMRWriter &);
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 0b79324..70c47ae 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -64,6 +64,8 @@
     bool isSeeking();
     bool reachedEOS(status_t *finalStatus);
 
+    status_t setPlaybackRatePermille(int32_t ratePermille);
+
 private:
     friend class VideoEditorAudioPlayer;
     sp<MediaSource> mSource;
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 19bd31b..79437bf 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -34,13 +34,13 @@
     // Note that the "channels" parameter is _not_ the number of channels,
     // but a bitmask of audio_channels_t constants.
     AudioSource(
-            int inputSource, uint32_t sampleRate,
+            audio_source_t inputSource, uint32_t sampleRate,
             uint32_t channels = AUDIO_CHANNEL_IN_MONO);
 
     status_t initCheck() const;
 
     virtual status_t start(MetaData *params = NULL);
-    virtual status_t stop();
+    virtual status_t stop() { return reset(); }
     virtual sp<MetaData> getFormat();
 
     // Returns the maximum amplitude since last call.
@@ -97,6 +97,7 @@
 
     void releaseQueuedFrames_l();
     void waitOutstandingEncodingFrames_l();
+    status_t reset();
 
     AudioSource(const AudioSource &);
     AudioSource &operator=(const AudioSource &);
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 446720b..5a35358 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -79,7 +79,7 @@
     virtual ~CameraSource();
 
     virtual status_t start(MetaData *params = NULL);
-    virtual status_t stop();
+    virtual status_t stop() { return reset(); }
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
 
@@ -163,7 +163,6 @@
                  bool storeMetaDataInVideoBuffers);
 
     virtual void startCameraRecording();
-    virtual void stopCameraRecording();
     virtual void releaseRecordingFrame(const sp<IMemory>& frame);
 
     // Returns true if need to skip the current frame.
@@ -220,7 +219,9 @@
     status_t checkFrameRate(const CameraParameters& params,
                     int32_t frameRate);
 
+    void stopCameraRecording();
     void releaseCamera();
+    status_t reset();
 
     CameraSource(const CameraSource &);
     CameraSource &operator=(const CameraSource &);
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index b060691..0936da2 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -121,9 +121,6 @@
     // Wrapper over CameraSource::read() to implement quick stop.
     virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL);
 
-    // For video camera case, just stops the camera's video recording.
-    virtual void stopCameraRecording();
-
     // mSkipCurrentFrame is set to true in dataCallbackTimestamp() if the current
     // frame needs to be skipped and this function just returns the value of mSkipCurrentFrame.
     virtual bool skipCurrentFrame(int64_t timestampUs);
diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h
index e4c1c49..a7c9ecf 100644
--- a/include/media/stagefright/MPEG2TSWriter.h
+++ b/include/media/stagefright/MPEG2TSWriter.h
@@ -37,7 +37,7 @@
 
     virtual status_t addSource(const sp<MediaSource> &source);
     virtual status_t start(MetaData *param = NULL);
-    virtual status_t stop();
+    virtual status_t stop() { return reset(); }
     virtual status_t pause();
     virtual bool reachedEOS();
     virtual status_t dump(int fd, const Vector<String16>& args);
@@ -78,6 +78,7 @@
     void writeAccessUnit(int32_t sourceIndex, const sp<ABuffer> &buffer);
 
     ssize_t internalWrite(const void *data, size_t size);
+    status_t reset();
 
     DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSWriter);
 };
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 77166ed..0409b30 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -37,7 +37,7 @@
 
     virtual status_t addSource(const sp<MediaSource> &source);
     virtual status_t start(MetaData *param = NULL);
-    virtual status_t stop();
+    virtual status_t stop() { return reset(); }
     virtual status_t pause();
     virtual bool reachedEOS();
     virtual status_t dump(int fd, const Vector<String16>& args);
@@ -184,6 +184,7 @@
     void writeLongitude(int degreex10000);
     void sendSessionSummary();
     void release();
+    status_t reset();
 
     MPEG4Writer(const MPEG4Writer &);
     MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h
deleted file mode 100644
index 2ca9667..0000000
--- a/include/media/stagefright/MediaDebug.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MEDIA_DEBUG_H_
-
-#define MEDIA_DEBUG_H_
-
-#include <cutils/log.h>
-
-#define LITERAL_TO_STRING_INTERNAL(x)    #x
-#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
-
-#define CHECK_EQ(x,y)                                                   \
-    LOG_ALWAYS_FATAL_IF(                                                \
-            (x) != (y),                                                 \
-            __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
-
-#define CHECK(x)                                                        \
-    LOG_ALWAYS_FATAL_IF(                                                \
-            !(x),                                                       \
-            __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
-
-#endif  // MEDIA_DEBUG_H_
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 84f8282..e541c18 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -172,6 +172,7 @@
     uint32_t mFlags;
 
     bool mIsEncoder;
+    bool mIsVideo;
     char *mMIME;
     char *mComponentName;
     sp<MetaData> mOutputFormat;
@@ -334,7 +335,7 @@
     status_t applyRotation();
     status_t waitForBufferFilled_l();
 
-    int64_t retrieveDecodingTimeUs(bool isCodecSpecific);
+    int64_t getDecodingTimeUs();
 
     status_t parseAVCCodecSpecificData(
             const void *data, size_t size,
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index d0940bb..54baab6 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -58,7 +58,7 @@
 
     // For the MediaSource interface for use by StageFrightRecorder:
     virtual status_t start(MetaData *params = NULL);
-    virtual status_t stop();
+    virtual status_t stop() { return reset(); }
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
     virtual sp<MetaData> getFormat();
@@ -359,6 +359,8 @@
     Condition mFrameAvailableCondition;
     Condition mFrameCompleteCondition;
 
+    status_t reset();
+
     // Avoid copying and equating and default constructor
     DISALLOW_IMPLICIT_CONSTRUCTORS(SurfaceMediaSource);
 };
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ffc546e..af2db93 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -54,6 +54,7 @@
 #define CBLK_RESTORED_ON        0x0040  // track has been restored after invalidation
 #define CBLK_RESTORED_OFF       0x0040  // by AudioFlinger
 
+// Important: do not add any virtual methods, including ~
 struct audio_track_cblk_t
 {
 
@@ -61,47 +62,66 @@
     // are in the same line of data cache.
                 Mutex       lock;           // sizeof(int)
                 Condition   cv;             // sizeof(int)
+
+                // next 4 are offsets within "buffers"
     volatile    uint32_t    user;
     volatile    uint32_t    server;
                 uint32_t    userBase;
                 uint32_t    serverBase;
+
+                // if there is a shared buffer, "buffers" is the value of pointer() for the shared
+                // buffer, otherwise "buffers" points immediately after the control block
                 void*       buffers;
                 uint32_t    frameCount;
+
                 // Cache line boundary
+
                 uint32_t    loopStart;
-                uint32_t    loopEnd;
-                int         loopCount;
+                uint32_t    loopEnd;        // read-only for server, read/write for client
+                int         loopCount;      // read/write for client
 
                 // Channel volumes are fixed point U4.12, so 0x1000 means 1.0.
                 // Left channel is in [0:15], right channel is in [16:31].
                 // Always read and write the combined pair atomically.
                 // For AudioTrack only, not used by AudioRecord.
-                uint32_t    volumeLR;
+private:
+                uint32_t    mVolumeLR;
+public:
 
                 uint32_t    sampleRate;
+
                 // NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for
                 // 8 bit PCM data: in this case,  mCblk->frameSize is based on a sample size of
                 // 16 bit because data is converted to 16 bit before being stored in buffer
 
+                // read-only for client, server writes once at initialization and is then read-only
                 uint8_t     frameSize;       // would normally be size_t, but 8 bits is plenty
+
+                // never used
                 uint8_t     pad1;
+
+                // used by client only
                 uint16_t    bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
 
-                uint16_t    waitTimeMs;      // Cumulated wait time
+                uint16_t    waitTimeMs;      // Cumulated wait time, used by client only
 private:
+                // client write-only, server read-only
                 uint16_t    mSendLevel;      // Fixed point U4.12 so 0x1000 means 1.0
 public:
     volatile    int32_t     flags;
 
                 // Cache line boundary (32 bytes)
 
+                // Since the control block is always located in shared memory, this constructor
+                // is only used for placement new().  It is never used for regular new() or stack.
                             audio_track_cblk_t();
-                uint32_t    stepUser(uint32_t frameCount);
-                bool        stepServer(uint32_t frameCount);
+                uint32_t    stepUser(uint32_t frameCount);      // called by client only, where
+                // client includes regular AudioTrack and AudioFlinger::PlaybackThread::OutputTrack
+                bool        stepServer(uint32_t frameCount);    // called by server only
                 void*       buffer(uint32_t offset) const;
                 uint32_t    framesAvailable();
                 uint32_t    framesAvailable_l();
-                uint32_t    framesReady();
+                uint32_t    framesReady();                      // called by server only
                 bool        tryLock();
 
                 // No barriers on the following operations, so the ordering of loads/stores
@@ -116,6 +136,17 @@
                 uint16_t    getSendLevel_U4_12() const {
                     return mSendLevel;
                 }
+
+                // for AudioTrack client only, caller must limit to 0 <= volumeLR <= 0x10001000
+                void        setVolumeLR(uint32_t volumeLR) {
+                    mVolumeLR = volumeLR;
+                }
+
+                // for AudioFlinger only; the return value must be validated by the caller
+                uint32_t    getVolumeLR() const {
+                    return mVolumeLR;
+                }
+
 };
 
 
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 95e4447..1f738cd 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -20,17 +20,13 @@
 /**
  * Native input transport.
  *
- * Uses anonymous shared memory as a whiteboard for sending input events from an
- * InputPublisher to an InputConsumer and ensuring appropriate synchronization.
- * One interesting feature is that published events can be updated in place as long as they
- * have not yet been consumed.
+ * The InputChannel provides a mechanism for exchanging InputMessage structures across processes.
  *
- * The InputPublisher and InputConsumer only take care of transferring event data
- * over an InputChannel and sending synchronization signals.  The InputDispatcher and InputQueue
- * build on these abstractions to add multiplexing and queueing.
+ * The InputPublisher and InputConsumer each handle one end-point of an input channel.
+ * The InputPublisher is used by the input dispatcher to send events to the application.
+ * The InputConsumer is used by the application to receive events from the input dispatcher.
  */
 
-#include <semaphore.h>
 #include <ui/Input.h>
 #include <utils/Errors.h>
 #include <utils/Timers.h>
@@ -40,88 +36,26 @@
 namespace android {
 
 /*
- * An input channel consists of a shared memory buffer and a pair of pipes
- * used to send input messages from an InputPublisher to an InputConsumer
- * across processes.  Each channel has a descriptive name for debugging purposes.
- *
- * Each endpoint has its own InputChannel object that specifies its own file descriptors.
- *
- * The input channel is closed when all references to it are released.
- */
-class InputChannel : public RefBase {
-protected:
-    virtual ~InputChannel();
-
-public:
-    InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
-            int32_t sendPipeFd);
-
-    /* Creates a pair of input channels and their underlying shared memory buffers
-     * and pipes.
-     *
-     * Returns OK on success.
-     */
-    static status_t openInputChannelPair(const String8& name,
-            sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
-
-    inline String8 getName() const { return mName; }
-    inline int32_t getAshmemFd() const { return mAshmemFd; }
-    inline int32_t getReceivePipeFd() const { return mReceivePipeFd; }
-    inline int32_t getSendPipeFd() const { return mSendPipeFd; }
-
-    /* Sends a signal to the other endpoint.
-     *
-     * Returns OK on success.
-     * Returns DEAD_OBJECT if the channel's peer has been closed.
-     * Other errors probably indicate that the channel is broken.
-     */
-    status_t sendSignal(char signal);
-
-    /* Receives a signal send by the other endpoint.
-     * (Should only call this after poll() indicates that the receivePipeFd has available input.)
-     *
-     * Returns OK on success.
-     * Returns WOULD_BLOCK if there is no signal present.
-     * Returns DEAD_OBJECT if the channel's peer has been closed.
-     * Other errors probably indicate that the channel is broken.
-     */
-    status_t receiveSignal(char* outSignal);
-
-private:
-    String8 mName;
-    int32_t mAshmemFd;
-    int32_t mReceivePipeFd;
-    int32_t mSendPipeFd;
-};
-
-/*
- * Private intermediate representation of input events as messages written into an
- * ashmem buffer.
+ * Intermediate representation used to send input events and related signals.
  */
 struct InputMessage {
-    /* Semaphore count is set to 1 when the message is published.
-     * It becomes 0 transiently while the publisher updates the message.
-     * It becomes 0 permanently when the consumer consumes the message.
-     */
-    sem_t semaphore;
-
-    /* Initialized to false by the publisher.
-     * Set to true by the consumer when it consumes the message.
-     */
-    bool consumed;
-
-    int32_t type;
-
-    struct SampleData {
-        nsecs_t eventTime;
-        PointerCoords coords[0]; // variable length
+    enum {
+        TYPE_KEY = 1,
+        TYPE_MOTION = 2,
+        TYPE_FINISHED = 3,
     };
 
-    int32_t deviceId;
-    int32_t source;
+    struct Header {
+        uint32_t type;
+        uint32_t padding; // 8 byte alignment for the body that follows
+    } header;
 
-    union {
-        struct {
+    union Body {
+        struct Key {
+            uint32_t seq;
+            nsecs_t eventTime;
+            int32_t deviceId;
+            int32_t source;
             int32_t action;
             int32_t flags;
             int32_t keyCode;
@@ -129,10 +63,17 @@
             int32_t metaState;
             int32_t repeatCount;
             nsecs_t downTime;
-            nsecs_t eventTime;
+
+            inline size_t size() const {
+                return sizeof(Key);
+            }
         } key;
 
-        struct {
+        struct Motion {
+            uint32_t seq;
+            nsecs_t eventTime;
+            int32_t deviceId;
+            int32_t source;
             int32_t action;
             int32_t flags;
             int32_t metaState;
@@ -144,28 +85,88 @@
             float xPrecision;
             float yPrecision;
             size_t pointerCount;
-            PointerProperties pointerProperties[MAX_POINTERS];
-            size_t sampleCount;
-            SampleData sampleData[0]; // variable length
+            struct Pointer {
+                PointerProperties properties;
+                PointerCoords coords;
+            } pointers[MAX_POINTERS];
+
+            inline size_t size() const {
+                return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS
+                        + sizeof(Pointer) * pointerCount;
+            }
         } motion;
-    };
 
-    /* Gets the number of bytes to add to step to the next SampleData object in a motion
-     * event message for a given number of pointers.
-     */
-    static inline size_t sampleDataStride(size_t pointerCount) {
-        return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords);
-    }
+        struct Finished {
+            uint32_t seq;
+            bool handled;
 
-    /* Adds the SampleData stride to the given pointer. */
-    static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) {
-        return reinterpret_cast<InputMessage::SampleData*>(reinterpret_cast<char*>(ptr) + stride);
-    }
+            inline size_t size() const {
+                return sizeof(Finished);
+            }
+        } finished;
+    } body;
+
+    bool isValid(size_t actualSize) const;
+    size_t size() const;
 };
 
 /*
- * Publishes input events to an anonymous shared memory buffer.
- * Uses atomic operations to coordinate shared access with a single concurrent consumer.
+ * An input channel consists of a local unix domain socket used to send and receive
+ * input messages across processes.  Each channel has a descriptive name for debugging purposes.
+ *
+ * Each endpoint has its own InputChannel object that specifies its file descriptor.
+ *
+ * The input channel is closed when all references to it are released.
+ */
+class InputChannel : public RefBase {
+protected:
+    virtual ~InputChannel();
+
+public:
+    InputChannel(const String8& name, int32_t fd);
+
+    /* Creates a pair of input channels.
+     *
+     * Returns OK on success.
+     */
+    static status_t openInputChannelPair(const String8& name,
+            sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
+
+    inline String8 getName() const { return mName; }
+    inline int32_t getFd() const { return mFd; }
+
+    /* Sends a message to the other endpoint.
+     *
+     * If the channel is full then the message is guaranteed not to have been sent at all.
+     * Try again after the consumer has sent a finished signal indicating that it has
+     * consumed some of the pending messages from the channel.
+     *
+     * Returns OK on success.
+     * Returns WOULD_BLOCK if the channel is full.
+     * Returns DEAD_OBJECT if the channel's peer has been closed.
+     * Other errors probably indicate that the channel is broken.
+     */
+    status_t sendMessage(const InputMessage* msg);
+
+    /* Receives a message sent by the other endpoint.
+     *
+     * If there is no message present, try again after poll() indicates that the fd
+     * is readable.
+     *
+     * Returns OK on success.
+     * Returns WOULD_BLOCK if there is no message present.
+     * Returns DEAD_OBJECT if the channel's peer has been closed.
+     * Other errors probably indicate that the channel is broken.
+     */
+    status_t receiveMessage(InputMessage* msg);
+
+private:
+    String8 mName;
+    int32_t mFd;
+};
+
+/*
+ * Publishes input events to an input channel.
  */
 class InputPublisher {
 public:
@@ -178,26 +179,16 @@
     /* Gets the underlying input channel. */
     inline sp<InputChannel> getChannel() { return mChannel; }
 
-    /* Prepares the publisher for use.  Must be called before it is used.
-     * Returns OK on success.
-     *
-     * This method implicitly calls reset(). */
-    status_t initialize();
-
-    /* Resets the publisher to its initial state and unpins its ashmem buffer.
-     * Returns OK on success.
-     *
-     * Should be called after an event has been consumed to release resources used by the
-     * publisher until the next event is ready to be published.
-     */
-    status_t reset();
-
-    /* Publishes a key event to the ashmem buffer.
+    /* Publishes a key event to the input channel.
      *
      * Returns OK on success.
-     * Returns INVALID_OPERATION if the publisher has not been reset.
+     * Returns WOULD_BLOCK if the channel is full.
+     * Returns DEAD_OBJECT if the channel's peer has been closed.
+     * Returns BAD_VALUE if seq is 0.
+     * Other errors probably indicate that the channel is broken.
      */
     status_t publishKeyEvent(
+            uint32_t seq,
             int32_t deviceId,
             int32_t source,
             int32_t action,
@@ -209,13 +200,16 @@
             nsecs_t downTime,
             nsecs_t eventTime);
 
-    /* Publishes a motion event to the ashmem buffer.
+    /* Publishes a motion event to the input channel.
      *
      * Returns OK on success.
-     * Returns INVALID_OPERATION if the publisher has not been reset.
-     * Returns BAD_VALUE if pointerCount is less than 1 or greater than MAX_POINTERS.
+     * Returns WOULD_BLOCK if the channel is full.
+     * Returns DEAD_OBJECT if the channel's peer has been closed.
+     * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS.
+     * Other errors probably indicate that the channel is broken.
      */
     status_t publishMotionEvent(
+            uint32_t seq,
             int32_t deviceId,
             int32_t source,
             int32_t action,
@@ -233,55 +227,25 @@
             const PointerProperties* pointerProperties,
             const PointerCoords* pointerCoords);
 
-    /* Appends a motion sample to a motion event unless already consumed.
-     *
-     * Returns OK on success.
-     * Returns INVALID_OPERATION if the current event is not a AMOTION_EVENT_ACTION_MOVE event.
-     * Returns FAILED_TRANSACTION if the current event has already been consumed.
-     * Returns NO_MEMORY if the buffer is full and no additional samples can be added.
-     */
-    status_t appendMotionSample(
-            nsecs_t eventTime,
-            const PointerCoords* pointerCoords);
-
-    /* Sends a dispatch signal to the consumer to inform it that a new message is available.
-     *
-     * Returns OK on success.
-     * Errors probably indicate that the channel is broken.
-     */
-    status_t sendDispatchSignal();
-
     /* Receives the finished signal from the consumer in reply to the original dispatch signal.
-     * Returns whether the consumer handled the message.
+     * If a signal was received, returns the message sequence number,
+     * and whether the consumer handled the message.
+     *
+     * The returned sequence number is never 0 unless the operation failed.
      *
      * Returns OK on success.
      * Returns WOULD_BLOCK if there is no signal present.
+     * Returns DEAD_OBJECT if the channel's peer has been closed.
      * Other errors probably indicate that the channel is broken.
      */
-    status_t receiveFinishedSignal(bool* outHandled);
+    status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
 
 private:
     sp<InputChannel> mChannel;
-
-    size_t mAshmemSize;
-    InputMessage* mSharedMessage;
-    bool mPinned;
-    bool mSemaphoreInitialized;
-    bool mWasDispatched;
-
-    size_t mMotionEventPointerCount;
-    InputMessage::SampleData* mMotionEventSampleDataTail;
-    size_t mMotionEventSampleDataStride;
-
-    status_t publishInputEvent(
-            int32_t type,
-            int32_t deviceId,
-            int32_t source);
 };
 
 /*
- * Consumes input events from an anonymous shared memory buffer.
- * Uses atomic operations to coordinate shared access with a single concurrent publisher.
+ * Consumes input events from an input channel.
  */
 class InputConsumer {
 public:
@@ -294,43 +258,76 @@
     /* Gets the underlying input channel. */
     inline sp<InputChannel> getChannel() { return mChannel; }
 
-    /* Prepares the consumer for use.  Must be called before it is used. */
-    status_t initialize();
-
-    /* Consumes the input event in the buffer and copies its contents into
+    /* Consumes an input event from the input channel and copies its contents into
      * an InputEvent object created using the specified factory.
-     * This operation will block if the publisher is updating the event.
+     *
+     * Tries to combine a series of move events into larger batches whenever possible.
+     *
+     * If consumeBatches is false, then defers consuming pending batched events if it
+     * is possible for additional samples to be added to them later.  Call hasPendingBatch()
+     * to determine whether a pending batch is available to be consumed.
+     *
+     * If consumeBatches is true, then events are still batched but they are consumed
+     * immediately as soon as the input channel is exhausted.
+     *
+     * The returned sequence number is never 0 unless the operation failed.
      *
      * Returns OK on success.
-     * Returns INVALID_OPERATION if there is no currently published event.
+     * Returns WOULD_BLOCK if there is no event present.
+     * Returns DEAD_OBJECT if the channel's peer has been closed.
      * Returns NO_MEMORY if the event could not be created.
-     */
-    status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent);
-
-    /* Sends a finished signal to the publisher to inform it that the current message is
-     * finished processing and specifies whether the message was handled by the consumer.
-     *
-     * Returns OK on success.
-     * Errors probably indicate that the channel is broken.
-     */
-    status_t sendFinishedSignal(bool handled);
-
-    /* Receives the dispatched signal from the publisher.
-     *
-     * Returns OK on success.
-     * Returns WOULD_BLOCK if there is no signal present.
      * Other errors probably indicate that the channel is broken.
      */
-    status_t receiveDispatchSignal();
+    status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
+            uint32_t* outSeq, InputEvent** outEvent);
+
+    /* Sends a finished signal to the publisher to inform it that the message
+     * with the specified sequence number has finished being process and whether
+     * the message was handled by the consumer.
+     *
+     * Returns OK on success.
+     * Returns BAD_VALUE if seq is 0.
+     * Other errors probably indicate that the channel is broken.
+     */
+    status_t sendFinishedSignal(uint32_t seq, bool handled);
+
+    /* Returns true if there is a pending batch. */
+    bool hasPendingBatch() const;
 
 private:
     sp<InputChannel> mChannel;
 
-    size_t mAshmemSize;
-    InputMessage* mSharedMessage;
+    // The current input message.
+    InputMessage mMsg;
 
-    void populateKeyEvent(KeyEvent* keyEvent) const;
-    void populateMotionEvent(MotionEvent* motionEvent) const;
+    // True if mMsg contains a valid input message that was deferred from the previous
+    // call to consume and that still needs to be handled.
+    bool mMsgDeferred;
+
+    // Batched motion events per device and source.
+    struct Batch {
+        uint32_t seq; // sequence number of last input message batched in the event
+        MotionEvent event;
+    };
+    Vector<Batch> mBatches;
+
+    // Chain of batched sequence numbers.  When multiple input messages are combined into
+    // a batch, we append a record here that associates the last sequence number in the
+    // batch with the previous one.  When the finished signal is sent, we traverse the
+    // chain to individually finish all input messages that were part of the batch.
+    struct SeqChain {
+        uint32_t seq;   // sequence number of batched input message
+        uint32_t chain; // sequence number of previous batched input message
+    };
+    Vector<SeqChain> mSeqChains;
+
+    ssize_t findBatch(int32_t deviceId, int32_t source) const;
+    status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
+
+    static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
+    static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
+    static bool canAppendSamples(const MotionEvent* event, const InputMessage* msg);
+    static void appendSamples(MotionEvent* event, const InputMessage* msg);
 };
 
 } // namespace android
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 6c9a620..f242f18 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -55,43 +55,51 @@
             void        set(uint32_t w, uint32_t h);
         
             Region&     orSelf(const Rect& rhs);
+            Region&     xorSelf(const Rect& rhs);
             Region&     andSelf(const Rect& rhs);
             Region&     subtractSelf(const Rect& rhs);
 
             // boolean operators, applied on this
             Region&     orSelf(const Region& rhs);
+            Region&     xorSelf(const Region& rhs);
             Region&     andSelf(const Region& rhs);
             Region&     subtractSelf(const Region& rhs);
 
             // boolean operators
     const   Region      merge(const Rect& rhs) const;
+    const   Region      mergeExclusive(const Rect& rhs) const;
     const   Region      intersect(const Rect& rhs) const;
     const   Region      subtract(const Rect& rhs) const;
 
             // boolean operators
     const   Region      merge(const Region& rhs) const;
+    const   Region      mergeExclusive(const Region& rhs) const;
     const   Region      intersect(const Region& rhs) const;
     const   Region      subtract(const Region& rhs) const;
 
             // these translate rhs first
             Region&     translateSelf(int dx, int dy);
             Region&     orSelf(const Region& rhs, int dx, int dy);
+            Region&     xorSelf(const Region& rhs, int dx, int dy);
             Region&     andSelf(const Region& rhs, int dx, int dy);
             Region&     subtractSelf(const Region& rhs, int dx, int dy);
 
             // these translate rhs first
     const   Region      translate(int dx, int dy) const;
     const   Region      merge(const Region& rhs, int dx, int dy) const;
+    const   Region      mergeExclusive(const Region& rhs, int dx, int dy) const;
     const   Region      intersect(const Region& rhs, int dx, int dy) const;
     const   Region      subtract(const Region& rhs, int dx, int dy) const;
 
     // convenience operators overloads
     inline  const Region      operator | (const Region& rhs) const;
+    inline  const Region      operator ^ (const Region& rhs) const;
     inline  const Region      operator & (const Region& rhs) const;
     inline  const Region      operator - (const Region& rhs) const;
     inline  const Region      operator + (const Point& pt) const;
 
     inline  Region&     operator |= (const Region& rhs);
+    inline  Region&     operator ^= (const Region& rhs);
     inline  Region&     operator &= (const Region& rhs);
     inline  Region&     operator -= (const Region& rhs);
     inline  Region&     operator += (const Point& pt);
@@ -158,6 +166,9 @@
 const Region Region::operator | (const Region& rhs) const {
     return merge(rhs);
 }
+const Region Region::operator ^ (const Region& rhs) const {
+    return mergeExclusive(rhs);
+}
 const Region Region::operator & (const Region& rhs) const {
     return intersect(rhs);
 }
@@ -172,6 +183,9 @@
 Region& Region::operator |= (const Region& rhs) {
     return orSelf(rhs);
 }
+Region& Region::operator ^= (const Region& rhs) {
+    return xorSelf(rhs);
+}
 Region& Region::operator &= (const Region& rhs) {
     return andSelf(rhs);
 }
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index 6bcdea4f..fcc3bcf 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -66,7 +66,7 @@
             ssize_t         indexOfKey(const KEY& key) const;
 
     /*!
-     * modifing the array
+     * modifying the array
      */
 
             VALUE&          editValueFor(const KEY& key);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 46420c1..c496da6 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -444,23 +444,31 @@
 
     void uninit();
 
+    // Return string entry as UTF16; if the pool is UTF8, the string will
+    // be converted before returning.
     inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const {
         return stringAt(ref.index, outLen);
     }
     const char16_t* stringAt(size_t idx, size_t* outLen) const;
 
+    // Note: returns null if the string pool is not UTF8.
     const char* string8At(size_t idx, size_t* outLen) const;
 
+    // Return string whether the pool is UTF8 or UTF16.  Does not allow you
+    // to distinguish null.
+    const String8 string8ObjectAt(size_t idx) const;
+
     const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const;
     const ResStringPool_span* styleAt(size_t idx) const;
 
     ssize_t indexOfString(const char16_t* str, size_t strLen) const;
 
     size_t size() const;
+    size_t styleCount() const;
+    size_t bytes() const;
 
-#ifndef HAVE_ANDROID_OS
+    bool isSorted() const;
     bool isUTF8() const;
-#endif
 
 private:
     status_t                    mError;
@@ -746,7 +754,9 @@
 /**
  * Header for a resource table.  Its data contains a series of
  * additional chunks:
- *   * A ResStringPool_header containing all table values.
+ *   * A ResStringPool_header containing all table values.  This string pool
+ *     contains all of the string values in the entire resource table (not
+ *     the names of entries or type identifiers however).
  *   * One or more ResTable_package chunks.
  *
  * Specific entries within a resource table can be uniquely identified
@@ -843,6 +853,8 @@
         DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM,
         DENSITY_TV = ACONFIGURATION_DENSITY_TV,
         DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH,
+        DENSITY_XHIGH = ACONFIGURATION_DENSITY_XHIGH,
+        DENSITY_XXHIGH = ACONFIGURATION_DENSITY_XXHIGH,
         DENSITY_NONE = ACONFIGURATION_DENSITY_NONE
     };
     
@@ -982,68 +994,15 @@
         uint32_t screenSizeDp;
     };
 
-    inline void copyFromDeviceNoSwap(const ResTable_config& o) {
-        const size_t size = dtohl(o.size);
-        if (size >= sizeof(ResTable_config)) {
-            *this = o;
-        } else {
-            memcpy(this, &o, size);
-            memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
-        }
-    }
+    void copyFromDeviceNoSwap(const ResTable_config& o);
     
-    inline void copyFromDtoH(const ResTable_config& o) {
-        copyFromDeviceNoSwap(o);
-        size = sizeof(ResTable_config);
-        mcc = dtohs(mcc);
-        mnc = dtohs(mnc);
-        density = dtohs(density);
-        screenWidth = dtohs(screenWidth);
-        screenHeight = dtohs(screenHeight);
-        sdkVersion = dtohs(sdkVersion);
-        minorVersion = dtohs(minorVersion);
-        smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
-        screenWidthDp = dtohs(screenWidthDp);
-        screenHeightDp = dtohs(screenHeightDp);
-    }
+    void copyFromDtoH(const ResTable_config& o);
     
-    inline void swapHtoD() {
-        size = htodl(size);
-        mcc = htods(mcc);
-        mnc = htods(mnc);
-        density = htods(density);
-        screenWidth = htods(screenWidth);
-        screenHeight = htods(screenHeight);
-        sdkVersion = htods(sdkVersion);
-        minorVersion = htods(minorVersion);
-        smallestScreenWidthDp = htods(smallestScreenWidthDp);
-        screenWidthDp = htods(screenWidthDp);
-        screenHeightDp = htods(screenHeightDp);
-    }
-    
-    inline int compare(const ResTable_config& o) const {
-        int32_t diff = (int32_t)(imsi - o.imsi);
-        if (diff != 0) return diff;
-        diff = (int32_t)(locale - o.locale);
-        if (diff != 0) return diff;
-        diff = (int32_t)(screenType - o.screenType);
-        if (diff != 0) return diff;
-        diff = (int32_t)(input - o.input);
-        if (diff != 0) return diff;
-        diff = (int32_t)(screenSize - o.screenSize);
-        if (diff != 0) return diff;
-        diff = (int32_t)(version - o.version);
-        if (diff != 0) return diff;
-        diff = (int32_t)(screenLayout - o.screenLayout);
-        if (diff != 0) return diff;
-        diff = (int32_t)(uiMode - o.uiMode);
-        if (diff != 0) return diff;
-        diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
-        if (diff != 0) return diff;
-        diff = (int32_t)(screenSizeDp - o.screenSizeDp);
-        return (int)diff;
-    }
-    
+    void swapHtoD();
+
+    int compare(const ResTable_config& o) const;
+    int compareLogical(const ResTable_config& o) const;
+
     // Flags indicating a set of config values.  These flag constants must
     // match the corresponding ones in android.content.pm.ActivityInfo and
     // attrs_manifest.xml.
@@ -1066,158 +1025,10 @@
     
     // Compare two configuration, returning CONFIG_* flags set for each value
     // that is different.
-    inline int diff(const ResTable_config& o) const {
-        int diffs = 0;
-        if (mcc != o.mcc) diffs |= CONFIG_MCC;
-        if (mnc != o.mnc) diffs |= CONFIG_MNC;
-        if (locale != o.locale) diffs |= CONFIG_LOCALE;
-        if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
-        if (density != o.density) diffs |= CONFIG_DENSITY;
-        if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
-        if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
-                diffs |= CONFIG_KEYBOARD_HIDDEN;
-        if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
-        if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
-        if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
-        if (version != o.version) diffs |= CONFIG_VERSION;
-        if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT;
-        if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
-        if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
-        if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
-        return diffs;
-    }
+    int diff(const ResTable_config& o) const;
     
     // Return true if 'this' is more specific than 'o'.
-    inline bool
-    isMoreSpecificThan(const ResTable_config& o) const {
-        // The order of the following tests defines the importance of one
-        // configuration parameter over another.  Those tests first are more
-        // important, trumping any values in those following them.
-        if (imsi || o.imsi) {
-            if (mcc != o.mcc) {
-                if (!mcc) return false;
-                if (!o.mcc) return true;
-            }
-
-            if (mnc != o.mnc) {
-                if (!mnc) return false;
-                if (!o.mnc) return true;
-            }
-        }
-
-        if (locale || o.locale) {
-            if (language[0] != o.language[0]) {
-                if (!language[0]) return false;
-                if (!o.language[0]) return true;
-            }
-
-            if (country[0] != o.country[0]) {
-                if (!country[0]) return false;
-                if (!o.country[0]) return true;
-            }
-        }
-
-        if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
-            if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
-                if (!smallestScreenWidthDp) return false;
-                if (!o.smallestScreenWidthDp) return true;
-            }
-        }
-
-        if (screenSizeDp || o.screenSizeDp) {
-            if (screenWidthDp != o.screenWidthDp) {
-                if (!screenWidthDp) return false;
-                if (!o.screenWidthDp) return true;
-            }
-
-            if (screenHeightDp != o.screenHeightDp) {
-                if (!screenHeightDp) return false;
-                if (!o.screenHeightDp) return true;
-            }
-        }
-
-        if (screenLayout || o.screenLayout) {
-            if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
-                if (!(screenLayout & MASK_SCREENSIZE)) return false;
-                if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
-            }
-            if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
-                if (!(screenLayout & MASK_SCREENLONG)) return false;
-                if (!(o.screenLayout & MASK_SCREENLONG)) return true;
-            }
-        }
-
-        if (orientation != o.orientation) {
-            if (!orientation) return false;
-            if (!o.orientation) return true;
-        }
-
-        if (uiMode || o.uiMode) {
-            if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) {
-                if (!(uiMode & MASK_UI_MODE_TYPE)) return false;
-                if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true;
-            }
-            if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) {
-                if (!(uiMode & MASK_UI_MODE_NIGHT)) return false;
-                if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true;
-            }
-        }
-
-        // density is never 'more specific'
-        // as the default just equals 160
-
-        if (touchscreen != o.touchscreen) {
-            if (!touchscreen) return false;
-            if (!o.touchscreen) return true;
-        }
-
-        if (input || o.input) {
-            if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) {
-                if (!(inputFlags & MASK_KEYSHIDDEN)) return false;
-                if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
-            }
-
-            if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
-                if (!(inputFlags & MASK_NAVHIDDEN)) return false;
-                if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
-            }
-
-            if (keyboard != o.keyboard) {
-                if (!keyboard) return false;
-                if (!o.keyboard) return true;
-            }
-
-            if (navigation != o.navigation) {
-                if (!navigation) return false;
-                if (!o.navigation) return true;
-            }
-        }
-
-        if (screenSize || o.screenSize) {
-            if (screenWidth != o.screenWidth) {
-                if (!screenWidth) return false;
-                if (!o.screenWidth) return true;
-            }
-
-            if (screenHeight != o.screenHeight) {
-                if (!screenHeight) return false;
-                if (!o.screenHeight) return true;
-            }
-        }
-
-        if (version || o.version) {
-            if (sdkVersion != o.sdkVersion) {
-                if (!sdkVersion) return false;
-                if (!o.sdkVersion) return true;
-            }
-
-            if (minorVersion != o.minorVersion) {
-                if (!minorVersion) return false;
-                if (!o.minorVersion) return true;
-            }
-        }
-        return false;
-    }
+    bool isMoreSpecificThan(const ResTable_config& o) const;
 
     // Return true if 'this' is a better match than 'o' for the 'requested'
     // configuration.  This assumes that match() has already been used to
@@ -1229,222 +1040,7 @@
     // they are not equal then one must be generic because only generic and
     // '==requested' will pass the match() call.  So if this is not generic,
     // it wins.  If this IS generic, o wins (return false).
-    inline bool
-    isBetterThan(const ResTable_config& o,
-            const ResTable_config* requested) const {
-        if (requested) {
-            if (imsi || o.imsi) {
-                if ((mcc != o.mcc) && requested->mcc) {
-                    return (mcc);
-                }
-
-                if ((mnc != o.mnc) && requested->mnc) {
-                    return (mnc);
-                }
-            }
-
-            if (locale || o.locale) {
-                if ((language[0] != o.language[0]) && requested->language[0]) {
-                    return (language[0]);
-                }
-
-                if ((country[0] != o.country[0]) && requested->country[0]) {
-                    return (country[0]);
-                }
-            }
-
-            if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
-                // The configuration closest to the actual size is best.
-                // We assume that larger configs have already been filtered
-                // out at this point.  That means we just want the largest one.
-                return smallestScreenWidthDp >= o.smallestScreenWidthDp;
-            }
-
-            if (screenSizeDp || o.screenSizeDp) {
-                // "Better" is based on the sum of the difference between both
-                // width and height from the requested dimensions.  We are
-                // assuming the invalid configs (with smaller dimens) have
-                // already been filtered.  Note that if a particular dimension
-                // is unspecified, we will end up with a large value (the
-                // difference between 0 and the requested dimension), which is
-                // good since we will prefer a config that has specified a
-                // dimension value.
-                int myDelta = 0, otherDelta = 0;
-                if (requested->screenWidthDp) {
-                    myDelta += requested->screenWidthDp - screenWidthDp;
-                    otherDelta += requested->screenWidthDp - o.screenWidthDp;
-                }
-                if (requested->screenHeightDp) {
-                    myDelta += requested->screenHeightDp - screenHeightDp;
-                    otherDelta += requested->screenHeightDp - o.screenHeightDp;
-                }
-                //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
-                //    screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
-                //    requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
-                return (myDelta <= otherDelta);
-            }
-
-            if (screenLayout || o.screenLayout) {
-                if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
-                        && (requested->screenLayout & MASK_SCREENSIZE)) {
-                    // A little backwards compatibility here: undefined is
-                    // considered equivalent to normal.  But only if the
-                    // requested size is at least normal; otherwise, small
-                    // is better than the default.
-                    int mySL = (screenLayout & MASK_SCREENSIZE);
-                    int oSL = (o.screenLayout & MASK_SCREENSIZE);
-                    int fixedMySL = mySL;
-                    int fixedOSL = oSL;
-                    if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
-                        if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
-                        if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
-                    }
-                    // For screen size, the best match is the one that is
-                    // closest to the requested screen size, but not over
-                    // (the not over part is dealt with in match() below).
-                    if (fixedMySL == fixedOSL) {
-                        // If the two are the same, but 'this' is actually
-                        // undefined, then the other is really a better match.
-                        if (mySL == 0) return false;
-                        return true;
-                    }
-                    return fixedMySL >= fixedOSL;
-                }
-                if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
-                        && (requested->screenLayout & MASK_SCREENLONG)) {
-                    return (screenLayout & MASK_SCREENLONG);
-                }
-            }
-
-            if ((orientation != o.orientation) && requested->orientation) {
-                return (orientation);
-            }
-
-            if (uiMode || o.uiMode) {
-                if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
-                        && (requested->uiMode & MASK_UI_MODE_TYPE)) {
-                    return (uiMode & MASK_UI_MODE_TYPE);
-                }
-                if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
-                        && (requested->uiMode & MASK_UI_MODE_NIGHT)) {
-                    return (uiMode & MASK_UI_MODE_NIGHT);
-                }
-            }
-
-            if (screenType || o.screenType) {
-                if (density != o.density) {
-                    // density is tough.  Any density is potentially useful
-                    // because the system will scale it.  Scaling down
-                    // is generally better than scaling up.
-                    // Default density counts as 160dpi (the system default)
-                    // TODO - remove 160 constants
-                    int h = (density?density:160);
-                    int l = (o.density?o.density:160);
-                    bool bImBigger = true;
-                    if (l > h) {
-                        int t = h;
-                        h = l;
-                        l = t;
-                        bImBigger = false;
-                    }
- 
-                    int reqValue = (requested->density?requested->density:160);
-                    if (reqValue >= h) {
-                        // requested value higher than both l and h, give h
-                        return bImBigger;
-                    }
-                    if (l >= reqValue) {
-                        // requested value lower than both l and h, give l
-                        return !bImBigger;
-                    }
-                    // saying that scaling down is 2x better than up
-                    if (((2 * l) - reqValue) * h > reqValue * reqValue) {
-                        return !bImBigger;
-                    } else { 
-                        return bImBigger;
-                    }
-                }
-
-                if ((touchscreen != o.touchscreen) && requested->touchscreen) {
-                    return (touchscreen);
-                }
-            }
-
-            if (input || o.input) {
-                const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
-                const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
-                if (keysHidden != oKeysHidden) {
-                    const int reqKeysHidden =
-                            requested->inputFlags & MASK_KEYSHIDDEN;
-                    if (reqKeysHidden) {
-
-                        if (!keysHidden) return false;
-                        if (!oKeysHidden) return true;
-                        // For compatibility, we count KEYSHIDDEN_NO as being
-                        // the same as KEYSHIDDEN_SOFT.  Here we disambiguate
-                        // these by making an exact match more specific.
-                        if (reqKeysHidden == keysHidden) return true;
-                        if (reqKeysHidden == oKeysHidden) return false;
-                    }
-                }
-
-                const int navHidden = inputFlags & MASK_NAVHIDDEN;
-                const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
-                if (navHidden != oNavHidden) {
-                    const int reqNavHidden =
-                            requested->inputFlags & MASK_NAVHIDDEN;
-                    if (reqNavHidden) {
-
-                        if (!navHidden) return false;
-                        if (!oNavHidden) return true;
-                    }
-                }
-
-                if ((keyboard != o.keyboard) && requested->keyboard) {
-                    return (keyboard);
-                }
-
-                if ((navigation != o.navigation) && requested->navigation) {
-                    return (navigation);
-                }
-            }
-
-            if (screenSize || o.screenSize) {
-                // "Better" is based on the sum of the difference between both
-                // width and height from the requested dimensions.  We are
-                // assuming the invalid configs (with smaller sizes) have
-                // already been filtered.  Note that if a particular dimension
-                // is unspecified, we will end up with a large value (the
-                // difference between 0 and the requested dimension), which is
-                // good since we will prefer a config that has specified a
-                // size value.
-                int myDelta = 0, otherDelta = 0;
-                if (requested->screenWidth) {
-                    myDelta += requested->screenWidth - screenWidth;
-                    otherDelta += requested->screenWidth - o.screenWidth;
-                }
-                if (requested->screenHeight) {
-                    myDelta += requested->screenHeight - screenHeight;
-                    otherDelta += requested->screenHeight - o.screenHeight;
-                }
-                return (myDelta <= otherDelta);
-            }
-
-            if (version || o.version) {
-                if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
-                    return (sdkVersion > o.sdkVersion);
-                }
-
-                if ((minorVersion != o.minorVersion) &&
-                        requested->minorVersion) {
-                    return (minorVersion);
-                }
-            }
-
-            return false;
-        }
-        return isMoreSpecificThan(o);
-    }
+    bool isBetterThan(const ResTable_config& o, const ResTable_config* requested) const;
 
     // Return true if 'this' can be considered a match for the parameters in 
     // 'settings'.
@@ -1452,150 +1048,11 @@
     // but a request for the default should not match odd specifics
     // (ie, request with no mcc should not match a particular mcc's data)
     // settings is the requested settings
-    inline bool match(const ResTable_config& settings) const {
-        if (imsi != 0) {
-            if (mcc != 0 && mcc != settings.mcc) {
-                return false;
-            }
-            if (mnc != 0 && mnc != settings.mnc) {
-                return false;
-            }
-        }
-        if (locale != 0) {
-            if (language[0] != 0
-                && (language[0] != settings.language[0]
-                    || language[1] != settings.language[1])) {
-                return false;
-            }
-            if (country[0] != 0
-                && (country[0] != settings.country[0]
-                    || country[1] != settings.country[1])) {
-                return false;
-            }
-        }
-        if (screenConfig != 0) {
-            const int screenSize = screenLayout&MASK_SCREENSIZE;
-            const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
-            // Any screen sizes for larger screens than the setting do not
-            // match.
-            if (screenSize != 0 && screenSize > setScreenSize) {
-                return false;
-            }
-            
-            const int screenLong = screenLayout&MASK_SCREENLONG;
-            const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
-            if (screenLong != 0 && screenLong != setScreenLong) {
-                return false;
-            }
+    bool match(const ResTable_config& settings) const;
 
-            const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
-            const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
-            if (uiModeType != 0 && uiModeType != setUiModeType) {
-                return false;
-            }
+    void getLocale(char str[6]) const;
 
-            const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
-            const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
-            if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
-                return false;
-            }
-
-            if (smallestScreenWidthDp != 0
-                    && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
-                return false;
-            }
-        }
-        if (screenSizeDp != 0) {
-            if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
-                //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
-                return false;
-            }
-            if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
-                //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
-                return false;
-            }
-        }
-        if (screenType != 0) {
-            if (orientation != 0 && orientation != settings.orientation) {
-                return false;
-            }
-            // density always matches - we can scale it.  See isBetterThan
-            if (touchscreen != 0 && touchscreen != settings.touchscreen) {
-                return false;
-            }
-        }
-        if (input != 0) {
-            const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
-            const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
-            if (keysHidden != 0 && keysHidden != setKeysHidden) {
-                // For compatibility, we count a request for KEYSHIDDEN_NO as also
-                // matching the more recent KEYSHIDDEN_SOFT.  Basically
-                // KEYSHIDDEN_NO means there is some kind of keyboard available.
-                //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
-                if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
-                    //ALOGI("No match!");
-                    return false;
-                }
-            }
-            const int navHidden = inputFlags&MASK_NAVHIDDEN;
-            const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
-            if (navHidden != 0 && navHidden != setNavHidden) {
-                return false;
-            }
-            if (keyboard != 0 && keyboard != settings.keyboard) {
-                return false;
-            }
-            if (navigation != 0 && navigation != settings.navigation) {
-                return false;
-            }
-        }
-        if (screenSize != 0) {
-            if (screenWidth != 0 && screenWidth > settings.screenWidth) {
-                return false;
-            }
-            if (screenHeight != 0 && screenHeight > settings.screenHeight) {
-                return false;
-            }
-        }
-        if (version != 0) {
-            if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
-                return false;
-            }
-            if (minorVersion != 0 && minorVersion != settings.minorVersion) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    void getLocale(char str[6]) const {
-        memset(str, 0, 6);
-        if (language[0]) {
-            str[0] = language[0];
-            str[1] = language[1];
-            if (country[0]) {
-                str[2] = '_';
-                str[3] = country[0];
-                str[4] = country[1];
-            }
-        }
-    }
-
-    String8 toString() const {
-        char buf[200];
-        sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=%d touch=%d dens=%d "
-                "kbd=%d nav=%d input=%d ssz=%dx%d sw%ddp w%ddp h%ddp sz=%d long=%d "
-                "ui=%d night=%d vers=%d.%d",
-                mcc, mnc,
-                language[0] ? language[0] : '-', language[1] ? language[1] : '-',
-                country[0] ? country[0] : '-', country[1] ? country[1] : '-',
-                orientation, touchscreen, density, keyboard, navigation, inputFlags,
-                screenWidth, screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
-                screenLayout&MASK_SCREENSIZE, screenLayout&MASK_SCREENLONG,
-                uiMode&MASK_UI_MODE_TYPE, uiMode&MASK_UI_MODE_NIGHT,
-                sdkVersion, minorVersion);
-        return String8(buf);
-    }
+    String8 toString() const;
 };
 
 /**
@@ -2054,8 +1511,14 @@
     const char16_t* getBasePackageName(size_t idx) const;
     uint32_t getBasePackageId(size_t idx) const;
 
+    // Return the number of resource tables that the object contains.
     size_t getTableCount() const;
+    // Return the values string pool for the resource table at the given
+    // index.  This string pool contains all of the strings for values
+    // contained in the resource table -- that is the item values themselves,
+    // but not the names their entries or types.
     const ResStringPool* getTableStringBlock(size_t index) const;
+    // Return unique cookie identifier for the given resource table.
     void* getTableCookie(size_t index) const;
 
     // Return the configurations (ResTable_config) that we know about
diff --git a/include/utils/threads.h b/include/utils/threads.h
index ab3e8cd..b4a8b7c 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -526,6 +526,12 @@
     // Do not call from this object's thread; will return WOULD_BLOCK in that case.
             status_t    join();
 
+#ifdef HAVE_ANDROID_OS
+    // Return the thread's kernel ID, same as the thread itself calling gettid() or
+    // androidGetTid(), or -1 if the thread is not running.
+            pid_t       getTid() const;
+#endif
+
 protected:
     // exitPending() returns true if requestExit() has been called.
             bool        exitPending() const;
@@ -551,8 +557,10 @@
     volatile bool           mExitPending;
     volatile bool           mRunning;
             sp<Thread>      mHoldSelf;
-#if HAVE_ANDROID_OS
-            int             mTid;
+#ifdef HAVE_ANDROID_OS
+    // legacy for debugging, not used by getTid() as it is set by the child thread
+    // and so is not initialized until the child reaches that point
+            pid_t           mTid;
 #endif
 };
 
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 629b899..b578a6c 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -371,6 +371,11 @@
     return mCallingUid;
 }
 
+int IPCThreadState::getOrigCallingUid()
+{
+    return mOrigCallingUid;
+}
+
 int64_t IPCThreadState::clearCallingIdentity()
 {
     int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
@@ -641,6 +646,7 @@
 {
     pthread_setspecific(gTLS, this);
     clearCaller();
+    mOrigCallingUid = mCallingUid;
     mIn.setDataCapacity(256);
     mOut.setDataCapacity(256);
 }
@@ -987,6 +993,7 @@
             
             mCallingPid = tr.sender_pid;
             mCallingUid = tr.sender_euid;
+            mOrigCallingUid = tr.sender_euid;
             
             int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
             if (gDisableBackgroundScheduling) {
@@ -1045,6 +1052,7 @@
             
             mCallingPid = origPid;
             mCallingUid = origUid;
+            mOrigCallingUid = origUid;
 
             IF_LOG_TRANSACTIONS() {
                 TextOutput::Bundle _b(alog);
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 33b305d..1750640 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -151,12 +151,14 @@
         return reply.readStrongBinder();
     }
 
-    virtual status_t addService(const String16& name, const sp<IBinder>& service)
+    virtual status_t addService(const String16& name, const sp<IBinder>& service,
+            bool allowIsolated)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
         data.writeString16(name);
         data.writeStrongBinder(service);
+        data.writeInt32(allowIsolated ? 1 : 0);
         status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
         return err == NO_ERROR ? reply.readExceptionCode() : err;
     }
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index b8be67d..2f4ac62 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -3,6 +3,7 @@
 
 LOCAL_SRC_FILES:= \
 	BitTube.cpp \
+	BufferQueue.cpp \
 	DisplayEventReceiver.cpp \
 	IDisplayEventConnection.cpp \
 	ISensorEventConnection.cpp \
@@ -34,6 +35,13 @@
 
 LOCAL_MODULE:= libgui
 
+ifeq ($(TARGET_BOARD_PLATFORM), omap4)
+	LOCAL_CFLAGS += -DUSE_FENCE_SYNC
+endif
+ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
+	LOCAL_CFLAGS += -DUSE_FENCE_SYNC
+endif
+
 ifeq ($(TARGET_BOARD_PLATFORM), tegra)
 	LOCAL_CFLAGS += -DALLOW_DEQUEUE_CURRENT_BUFFER
 endif
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index 785da39..55f4178 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -17,8 +17,9 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <unistd.h>
 #include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
 
 #include <utils/Errors.h>
 
@@ -38,6 +39,8 @@
         mSendFd = fds[1];
         fcntl(mReceiveFd, F_SETFL, O_NONBLOCK);
         fcntl(mSendFd, F_SETFL, O_NONBLOCK);
+        // ignore SIGPIPE, we handle write errors through EPIPE instead
+        signal(SIGPIPE, SIG_IGN);
     } else {
         mReceiveFd = -errno;
         ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd));
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
new file mode 100644
index 0000000..c7e2c0f
--- /dev/null
+++ b/libs/gui/BufferQueue.cpp
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferQueue"
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <gui/BufferQueue.h>
+#include <private/gui/ComposerService.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+
+#include <utils/Log.h>
+
+// This compile option causes SurfaceTexture to return the buffer that is currently
+// attached to the GL texture from dequeueBuffer when no other buffers are
+// available.  It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
+// implicit cross-process synchronization to prevent the buffer from being
+// written to before the buffer has (a) been detached from the GL texture and
+// (b) all GL reads from the buffer have completed.
+#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
+#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    true
+#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
+#else
+#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    false
+#endif
+
+// Macros for including the BufferQueue name in log messages
+#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
+
+BufferQueue::BufferQueue( bool allowSynchronousMode ) :
+    mDefaultWidth(1),
+    mDefaultHeight(1),
+    mPixelFormat(PIXEL_FORMAT_RGBA_8888),
+    mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
+    mClientBufferCount(0),
+    mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
+    mCurrentTexture(INVALID_BUFFER_SLOT),
+    mNextTransform(0),
+    mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+    mSynchronousMode(false),
+    mAllowSynchronousMode(allowSynchronousMode),
+    mConnectedApi(NO_CONNECTED_API),
+    mAbandoned(false),
+    mFrameCounter(0)
+{
+    // Choose a name using the PID and a process-unique ID.
+    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+    ST_LOGV("BufferQueue");
+    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+    mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
+    mNextCrop.makeInvalid();
+}
+
+BufferQueue::~BufferQueue() {
+    ST_LOGV("~BufferQueue");
+}
+
+status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
+    if (bufferCount > NUM_BUFFER_SLOTS)
+        return BAD_VALUE;
+
+    // special-case, nothing to do
+    if (bufferCount == mBufferCount)
+        return OK;
+
+    if (!mClientBufferCount &&
+        bufferCount >= mBufferCount) {
+        // easy, we just have more buffers
+        mBufferCount = bufferCount;
+        mServerBufferCount = bufferCount;
+        mDequeueCondition.signal();
+    } else {
+        // we're here because we're either
+        // - reducing the number of available buffers
+        // - or there is a client-buffer-count in effect
+
+        // less than 2 buffers is never allowed
+        if (bufferCount < 2)
+            return BAD_VALUE;
+
+        // when there is non client-buffer-count in effect, the client is not
+        // allowed to dequeue more than one buffer at a time,
+        // so the next time they dequeue a buffer, we know that they don't
+        // own one. the actual resizing will happen during the next
+        // dequeueBuffer.
+
+        mServerBufferCount = bufferCount;
+    }
+    return OK;
+}
+
+status_t BufferQueue::setBufferCount(int bufferCount) {
+    ST_LOGV("setBufferCount: count=%d", bufferCount);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
+    if (bufferCount > NUM_BUFFER_SLOTS) {
+        ST_LOGE("setBufferCount: bufferCount larger than slots available");
+        return BAD_VALUE;
+    }
+
+    // Error out if the user has dequeued buffers
+    for (int i=0 ; i<mBufferCount ; i++) {
+        if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
+            ST_LOGE("setBufferCount: client owns some buffers");
+            return -EINVAL;
+        }
+    }
+
+    const int minBufferSlots = mSynchronousMode ?
+            MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+    if (bufferCount == 0) {
+        mClientBufferCount = 0;
+        bufferCount = (mServerBufferCount >= minBufferSlots) ?
+                mServerBufferCount : minBufferSlots;
+        return setBufferCountServerLocked(bufferCount);
+    }
+
+    if (bufferCount < minBufferSlots) {
+        ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
+                "minimum (%d)", bufferCount, minBufferSlots);
+        return BAD_VALUE;
+    }
+
+    // here we're guaranteed that the client doesn't have dequeued buffers
+    // and will release all of its buffer references.
+    freeAllBuffersLocked();
+    mBufferCount = bufferCount;
+    mClientBufferCount = bufferCount;
+    mCurrentTexture = INVALID_BUFFER_SLOT;
+    mQueue.clear();
+    mDequeueCondition.signal();
+    return OK;
+}
+
+status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    ST_LOGV("requestBuffer: slot=%d", slot);
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
+    if (slot < 0 || mBufferCount <= slot) {
+        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+                mBufferCount, slot);
+        return BAD_VALUE;
+    }
+    mSlots[slot].mRequestBufferCalled = true;
+    *buf = mSlots[slot].mGraphicBuffer;
+    return NO_ERROR;
+}
+
+status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
+        uint32_t format, uint32_t usage) {
+    ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
+
+    if ((w && !h) || (!w && h)) {
+        ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
+        return BAD_VALUE;
+    }
+
+    status_t returnFlags(OK);
+    EGLDisplay dpy = EGL_NO_DISPLAY;
+    EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+
+    { // Scope for the lock
+        Mutex::Autolock lock(mMutex);
+
+        int found = -1;
+        int foundSync = -1;
+        int dequeuedCount = 0;
+        bool tryAgain = true;
+        while (tryAgain) {
+            if (mAbandoned) {
+                ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+                return NO_INIT;
+            }
+
+            // We need to wait for the FIFO to drain if the number of buffer
+            // needs to change.
+            //
+            // The condition "number of buffers needs to change" is true if
+            // - the client doesn't care about how many buffers there are
+            // - AND the actual number of buffer is different from what was
+            //   set in the last setBufferCountServer()
+            //                         - OR -
+            //   setBufferCountServer() was set to a value incompatible with
+            //   the synchronization mode (for instance because the sync mode
+            //   changed since)
+            //
+            // As long as this condition is true AND the FIFO is not empty, we
+            // wait on mDequeueCondition.
+
+            const int minBufferCountNeeded = mSynchronousMode ?
+                    MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+
+            const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
+                    ((mServerBufferCount != mBufferCount) ||
+                            (mServerBufferCount < minBufferCountNeeded));
+
+            if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
+                // wait for the FIFO to drain
+                mDequeueCondition.wait(mMutex);
+                // NOTE: we continue here because we need to reevaluate our
+                // whole state (eg: we could be abandoned or disconnected)
+                continue;
+            }
+
+            if (numberOfBuffersNeedsToChange) {
+                // here we're guaranteed that mQueue is empty
+                freeAllBuffersLocked();
+                mBufferCount = mServerBufferCount;
+                if (mBufferCount < minBufferCountNeeded)
+                    mBufferCount = minBufferCountNeeded;
+                mCurrentTexture = INVALID_BUFFER_SLOT;
+                returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+            }
+
+            // look for a free buffer to give to the client
+            found = INVALID_BUFFER_SLOT;
+            foundSync = INVALID_BUFFER_SLOT;
+            dequeuedCount = 0;
+            for (int i = 0; i < mBufferCount; i++) {
+                const int state = mSlots[i].mBufferState;
+                if (state == BufferSlot::DEQUEUED) {
+                    dequeuedCount++;
+                }
+
+                // if buffer is FREE it CANNOT be current
+                ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
+                        "dequeueBuffer: buffer %d is both FREE and current!",
+                        i);
+
+                if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
+                    if (state == BufferSlot::FREE || i == mCurrentTexture) {
+                        foundSync = i;
+                        if (i != mCurrentTexture) {
+                            found = i;
+                            break;
+                        }
+                    }
+                } else {
+                    if (state == BufferSlot::FREE) {
+                        /* We return the oldest of the free buffers to avoid
+                         * stalling the producer if possible.  This is because
+                         * the consumer may still have pending reads of the
+                         * buffers in flight.
+                         */
+                        bool isOlder = mSlots[i].mFrameNumber <
+                                mSlots[found].mFrameNumber;
+                        if (found < 0 || isOlder) {
+                            foundSync = i;
+                            found = i;
+                        }
+                    }
+                }
+            }
+
+            // clients are not allowed to dequeue more than one buffer
+            // if they didn't set a buffer count.
+            if (!mClientBufferCount && dequeuedCount) {
+                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
+                        "setting the buffer count");
+                return -EINVAL;
+            }
+
+            // See whether a buffer has been queued since the last
+            // setBufferCount so we know whether to perform the
+            // MIN_UNDEQUEUED_BUFFERS check below.
+            bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
+            if (bufferHasBeenQueued) {
+                // make sure the client is not trying to dequeue more buffers
+                // than allowed.
+                const int avail = mBufferCount - (dequeuedCount+1);
+                if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
+                    ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
+                            "(dequeued=%d)",
+                            MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
+                            dequeuedCount);
+                    return -EBUSY;
+                }
+            }
+
+            // we're in synchronous mode and didn't find a buffer, we need to
+            // wait for some buffers to be consumed
+            tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
+            if (tryAgain) {
+                mDequeueCondition.wait(mMutex);
+            }
+        }
+
+        if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
+            // foundSync guaranteed to be != INVALID_BUFFER_SLOT
+            found = foundSync;
+        }
+
+        if (found == INVALID_BUFFER_SLOT) {
+            // This should not happen.
+            ST_LOGE("dequeueBuffer: no available buffer slots");
+            return -EBUSY;
+        }
+
+        const int buf = found;
+        *outBuf = found;
+
+        const bool useDefaultSize = !w && !h;
+        if (useDefaultSize) {
+            // use the default size
+            w = mDefaultWidth;
+            h = mDefaultHeight;
+        }
+
+        const bool updateFormat = (format != 0);
+        if (!updateFormat) {
+            // keep the current (or default) format
+            format = mPixelFormat;
+        }
+
+        // buffer is now in DEQUEUED (but can also be current at the same time,
+        // if we're in synchronous mode)
+        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+
+        const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+        if ((buffer == NULL) ||
+            (uint32_t(buffer->width)  != w) ||
+            (uint32_t(buffer->height) != h) ||
+            (uint32_t(buffer->format) != format) ||
+            ((uint32_t(buffer->usage) & usage) != usage))
+        {
+            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+            status_t error;
+            sp<GraphicBuffer> graphicBuffer(
+                    mGraphicBufferAlloc->createGraphicBuffer(
+                            w, h, format, usage, &error));
+            if (graphicBuffer == 0) {
+                ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
+                        "failed");
+                return error;
+            }
+            if (updateFormat) {
+                mPixelFormat = format;
+            }
+            mSlots[buf].mGraphicBuffer = graphicBuffer;
+            mSlots[buf].mRequestBufferCalled = false;
+            mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+            if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
+                eglDestroyImageKHR(mSlots[buf].mEglDisplay,
+                        mSlots[buf].mEglImage);
+                mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
+                mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+            }
+            if (mCurrentTexture == buf) {
+                // The current texture no longer references the buffer in this slot
+                // since we just allocated a new buffer.
+                mCurrentTexture = INVALID_BUFFER_SLOT;
+            }
+            returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
+        }
+
+        dpy = mSlots[buf].mEglDisplay;
+        fence = mSlots[buf].mFence;
+        mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+    }
+
+    if (fence != EGL_NO_SYNC_KHR) {
+        EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+        // If something goes wrong, log the error, but return the buffer without
+        // synchronizing access to it.  It's too late at this point to abort the
+        // dequeue operation.
+        if (result == EGL_FALSE) {
+            ALOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
+        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            ALOGE("dequeueBuffer: timeout waiting for fence");
+        }
+        eglDestroySyncKHR(dpy, fence);
+    }
+
+    ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
+            mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
+
+    return returnFlags;
+}
+
+status_t BufferQueue::setSynchronousMode(bool enabled) {
+    ST_LOGV("setSynchronousMode: enabled=%d", enabled);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
+
+    status_t err = OK;
+    if (!mAllowSynchronousMode && enabled)
+        return err;
+
+    if (!enabled) {
+        // going to asynchronous mode, drain the queue
+        err = drainQueueLocked();
+        if (err != NO_ERROR)
+            return err;
+    }
+
+    if (mSynchronousMode != enabled) {
+        // - if we're going to asynchronous mode, the queue is guaranteed to be
+        // empty here
+        // - if the client set the number of buffers, we're guaranteed that
+        // we have at least 3 (because we don't allow less)
+        mSynchronousMode = enabled;
+        mDequeueCondition.signal();
+    }
+    return err;
+}
+
+status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+    ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
+
+    sp<FrameAvailableListener> listener;
+
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        if (mAbandoned) {
+            ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
+            return NO_INIT;
+        }
+        if (buf < 0 || buf >= mBufferCount) {
+            ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
+                    mBufferCount, buf);
+            return -EINVAL;
+        } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+            ST_LOGE("queueBuffer: slot %d is not owned by the client "
+                    "(state=%d)", buf, mSlots[buf].mBufferState);
+            return -EINVAL;
+        } else if (buf == mCurrentTexture) {
+            ST_LOGE("queueBuffer: slot %d is current!", buf);
+            return -EINVAL;
+        } else if (!mSlots[buf].mRequestBufferCalled) {
+            ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
+                    "buffer", buf);
+            return -EINVAL;
+        }
+
+        if (mSynchronousMode) {
+            // In synchronous mode we queue all buffers in a FIFO.
+            mQueue.push_back(buf);
+
+            // Synchronous mode always signals that an additional frame should
+            // be consumed.
+            listener = mFrameAvailableListener;
+        } else {
+            // In asynchronous mode we only keep the most recent buffer.
+            if (mQueue.empty()) {
+                mQueue.push_back(buf);
+
+                // Asynchronous mode only signals that a frame should be
+                // consumed if no previous frame was pending. If a frame were
+                // pending then the consumer would have already been notified.
+                listener = mFrameAvailableListener;
+            } else {
+                Fifo::iterator front(mQueue.begin());
+                // buffer currently queued is freed
+                mSlots[*front].mBufferState = BufferSlot::FREE;
+                // and we record the new buffer index in the queued list
+                *front = buf;
+            }
+        }
+
+        mSlots[buf].mBufferState = BufferSlot::QUEUED;
+        mSlots[buf].mCrop = mNextCrop;
+        mSlots[buf].mTransform = mNextTransform;
+        mSlots[buf].mScalingMode = mNextScalingMode;
+        mSlots[buf].mTimestamp = timestamp;
+        mFrameCounter++;
+        mSlots[buf].mFrameNumber = mFrameCounter;
+
+        mDequeueCondition.signal();
+
+        *outWidth = mDefaultWidth;
+        *outHeight = mDefaultHeight;
+        *outTransform = 0;
+    } // scope for the lock
+
+    // call back without lock held
+    if (listener != 0) {
+        listener->onFrameAvailable();
+    }
+    return OK;
+}
+
+void BufferQueue::cancelBuffer(int buf) {
+    ST_LOGV("cancelBuffer: slot=%d", buf);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGW("cancelBuffer: BufferQueue has been abandoned!");
+        return;
+    }
+
+    if (buf < 0 || buf >= mBufferCount) {
+        ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
+                mBufferCount, buf);
+        return;
+    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+        ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
+                buf, mSlots[buf].mBufferState);
+        return;
+    }
+    mSlots[buf].mBufferState = BufferSlot::FREE;
+    mSlots[buf].mFrameNumber = 0;
+    mDequeueCondition.signal();
+}
+
+status_t BufferQueue::setCrop(const Rect& crop) {
+    ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
+            crop.bottom);
+
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        ST_LOGE("setCrop: BufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+    mNextCrop = crop;
+    return OK;
+}
+
+status_t BufferQueue::setTransform(uint32_t transform) {
+    ST_LOGV("setTransform: xform=%#x", transform);
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        ST_LOGE("setTransform: BufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+    mNextTransform = transform;
+    return OK;
+}
+
+status_t BufferQueue::setScalingMode(int mode) {
+    ST_LOGV("setScalingMode: mode=%d", mode);
+
+    switch (mode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+            break;
+        default:
+            ST_LOGE("unknown scaling mode: %d", mode);
+            return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mNextScalingMode = mode;
+    return OK;
+}
+
+status_t BufferQueue::connect(int api,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+    ST_LOGV("connect: api=%d", api);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("connect: BufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            if (mConnectedApi != NO_CONNECTED_API) {
+                ST_LOGE("connect: already connected (cur=%d, req=%d)",
+                        mConnectedApi, api);
+                err = -EINVAL;
+            } else {
+                mConnectedApi = api;
+                *outWidth = mDefaultWidth;
+                *outHeight = mDefaultHeight;
+                *outTransform = 0;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
+status_t BufferQueue::disconnect(int api) {
+    ST_LOGV("disconnect: api=%d", api);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        // it is not really an error to disconnect after the surface
+        // has been abandoned, it should just be a no-op.
+        return NO_ERROR;
+    }
+
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            if (mConnectedApi == api) {
+                drainQueueAndFreeBuffersLocked();
+                mConnectedApi = NO_CONNECTED_API;
+                mNextCrop.makeInvalid();
+                mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+                mNextTransform = 0;
+                mDequeueCondition.signal();
+            } else {
+                ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+                        mConnectedApi, api);
+                err = -EINVAL;
+            }
+            break;
+        default:
+            ST_LOGE("disconnect: unknown API %d", api);
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
+void BufferQueue::freeBufferLocked(int i) {
+    mSlots[i].mGraphicBuffer = 0;
+    mSlots[i].mBufferState = BufferSlot::FREE;
+    mSlots[i].mFrameNumber = 0;
+    if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
+        mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+void BufferQueue::freeAllBuffersLocked() {
+    ALOGW_IF(!mQueue.isEmpty(),
+            "freeAllBuffersLocked called but mQueue is not empty");
+    mCurrentTexture = INVALID_BUFFER_SLOT;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        freeBufferLocked(i);
+    }
+}
+
+void BufferQueue::freeAllBuffersExceptHeadLocked() {
+    ALOGW_IF(!mQueue.isEmpty(),
+            "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
+    int head = -1;
+    if (!mQueue.empty()) {
+        Fifo::iterator front(mQueue.begin());
+        head = *front;
+    }
+    mCurrentTexture = INVALID_BUFFER_SLOT;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (i != head) {
+            freeBufferLocked(i);
+        }
+    }
+}
+
+status_t BufferQueue::drainQueueLocked() {
+    while (mSynchronousMode && !mQueue.isEmpty()) {
+        mDequeueCondition.wait(mMutex);
+        if (mAbandoned) {
+            ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
+            return NO_INIT;
+        }
+        if (mConnectedApi == NO_CONNECTED_API) {
+            ST_LOGE("drainQueueLocked: BufferQueue is not connected!");
+            return NO_INIT;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
+    status_t err = drainQueueLocked();
+    if (err == NO_ERROR) {
+        if (mSynchronousMode) {
+            freeAllBuffersLocked();
+        } else {
+            freeAllBuffersExceptHeadLocked();
+        }
+    }
+    return err;
+}
+
+}; // namespace android
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 3b3ccaa..6a4763d 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -80,7 +80,13 @@
 
 ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
         size_t count) {
-    ssize_t size = mDataChannel->read(events, sizeof(events[0])*count);
+    return DisplayEventReceiver::getEvents(mDataChannel, events, count);
+}
+
+ssize_t DisplayEventReceiver::getEvents(const sp<BitTube>& dataChannel,
+        Event* events, size_t count)
+{
+    ssize_t size = dataChannel->read(events, sizeof(events[0])*count);
     ALOGE_IF(size<0,
             "DisplayEventReceiver::getEvents error (%s)",
             strerror(-size));
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 3abe84a..be1bcd1 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -38,19 +38,6 @@
 #include <utils/Log.h>
 #include <utils/String8.h>
 
-// This compile option causes SurfaceTexture to return the buffer that is currently
-// attached to the GL texture from dequeueBuffer when no other buffers are
-// available.  It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
-// implicit cross-process synchronization to prevent the buffer from being
-// written to before the buffer has (a) been detached from the GL texture and
-// (b) all GL reads from the buffer have completed.
-#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
-#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    true
-#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
-#else
-#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    false
-#endif
-
 // This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
 // to synchronize access to the buffers.  It will cause dequeueBuffer to stall,
 // waiting for the GL reads for the buffer being dequeued to complete before
@@ -110,44 +97,22 @@
 
 static void mtxMul(float out[16], const float a[16], const float b[16]);
 
-// Get an ID that's unique within this process.
-static int32_t createProcessUniqueId() {
-    static volatile int32_t globalCounter = 0;
-    return android_atomic_inc(&globalCounter);
-}
 
 SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
         GLenum texTarget, bool useFenceSync) :
-    mDefaultWidth(1),
-    mDefaultHeight(1),
-    mPixelFormat(PIXEL_FORMAT_RGBA_8888),
-    mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
-    mClientBufferCount(0),
-    mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
-    mCurrentTexture(INVALID_BUFFER_SLOT),
+    BufferQueue(allowSynchronousMode),
     mCurrentTransform(0),
     mCurrentTimestamp(0),
-    mNextTransform(0),
-    mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mTexName(tex),
-    mSynchronousMode(false),
-    mAllowSynchronousMode(allowSynchronousMode),
-    mConnectedApi(NO_CONNECTED_API),
-    mAbandoned(false),
 #ifdef USE_FENCE_SYNC
     mUseFenceSync(useFenceSync),
 #else
     mUseFenceSync(false),
 #endif
-    mTexTarget(texTarget),
-    mFrameCounter(0) {
-    // Choose a name using the PID and a process-unique ID.
-    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+    mTexTarget(texTarget)
+{
 
     ST_LOGV("SurfaceTexture");
-    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
-    mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
-    mNextCrop.makeInvalid();
     memcpy(mCurrentTransformMatrix, mtxIdentity,
             sizeof(mCurrentTransformMatrix));
 }
@@ -157,91 +122,11 @@
     freeAllBuffersLocked();
 }
 
-status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) {
-    if (bufferCount > NUM_BUFFER_SLOTS)
-        return BAD_VALUE;
-
-    // special-case, nothing to do
-    if (bufferCount == mBufferCount)
-        return OK;
-
-    if (!mClientBufferCount &&
-        bufferCount >= mBufferCount) {
-        // easy, we just have more buffers
-        mBufferCount = bufferCount;
-        mServerBufferCount = bufferCount;
-        mDequeueCondition.signal();
-    } else {
-        // we're here because we're either
-        // - reducing the number of available buffers
-        // - or there is a client-buffer-count in effect
-
-        // less than 2 buffers is never allowed
-        if (bufferCount < 2)
-            return BAD_VALUE;
-
-        // when there is non client-buffer-count in effect, the client is not
-        // allowed to dequeue more than one buffer at a time,
-        // so the next time they dequeue a buffer, we know that they don't
-        // own one. the actual resizing will happen during the next
-        // dequeueBuffer.
-
-        mServerBufferCount = bufferCount;
-    }
-    return OK;
-}
-
 status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
     Mutex::Autolock lock(mMutex);
     return setBufferCountServerLocked(bufferCount);
 }
 
-status_t SurfaceTexture::setBufferCount(int bufferCount) {
-    ST_LOGV("setBufferCount: count=%d", bufferCount);
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
-        return NO_INIT;
-    }
-    if (bufferCount > NUM_BUFFER_SLOTS) {
-        ST_LOGE("setBufferCount: bufferCount larger than slots available");
-        return BAD_VALUE;
-    }
-
-    // Error out if the user has dequeued buffers
-    for (int i=0 ; i<mBufferCount ; i++) {
-        if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
-            ST_LOGE("setBufferCount: client owns some buffers");
-            return -EINVAL;
-        }
-    }
-
-    const int minBufferSlots = mSynchronousMode ?
-            MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
-    if (bufferCount == 0) {
-        mClientBufferCount = 0;
-        bufferCount = (mServerBufferCount >= minBufferSlots) ?
-                mServerBufferCount : minBufferSlots;
-        return setBufferCountServerLocked(bufferCount);
-    }
-
-    if (bufferCount < minBufferSlots) {
-        ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
-                "minimum (%d)", bufferCount, minBufferSlots);
-        return BAD_VALUE;
-    }
-
-    // here we're guaranteed that the client doesn't have dequeued buffers
-    // and will release all of its buffer references.
-    freeAllBuffersLocked();
-    mBufferCount = bufferCount;
-    mClientBufferCount = bufferCount;
-    mCurrentTexture = INVALID_BUFFER_SLOT;
-    mQueue.clear();
-    mDequeueCondition.signal();
-    return OK;
-}
 
 status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
 {
@@ -258,496 +143,6 @@
     return OK;
 }
 
-status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
-    ST_LOGV("requestBuffer: slot=%d", slot);
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
-        return NO_INIT;
-    }
-    if (slot < 0 || mBufferCount <= slot) {
-        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
-                mBufferCount, slot);
-        return BAD_VALUE;
-    }
-    mSlots[slot].mRequestBufferCalled = true;
-    *buf = mSlots[slot].mGraphicBuffer;
-    return NO_ERROR;
-}
-
-status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
-        uint32_t format, uint32_t usage) {
-    ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
-
-    if ((w && !h) || (!w && h)) {
-        ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
-        return BAD_VALUE;
-    }
-
-    status_t returnFlags(OK);
-    EGLDisplay dpy = EGL_NO_DISPLAY;
-    EGLSyncKHR fence = EGL_NO_SYNC_KHR;
-
-    { // Scope for the lock
-        Mutex::Autolock lock(mMutex);
-
-        int found = -1;
-        int foundSync = -1;
-        int dequeuedCount = 0;
-        bool tryAgain = true;
-        while (tryAgain) {
-            if (mAbandoned) {
-                ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
-                return NO_INIT;
-            }
-
-            // We need to wait for the FIFO to drain if the number of buffer
-            // needs to change.
-            //
-            // The condition "number of buffers needs to change" is true if
-            // - the client doesn't care about how many buffers there are
-            // - AND the actual number of buffer is different from what was
-            //   set in the last setBufferCountServer()
-            //                         - OR -
-            //   setBufferCountServer() was set to a value incompatible with
-            //   the synchronization mode (for instance because the sync mode
-            //   changed since)
-            //
-            // As long as this condition is true AND the FIFO is not empty, we
-            // wait on mDequeueCondition.
-
-            const int minBufferCountNeeded = mSynchronousMode ?
-                    MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
-
-            const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
-                    ((mServerBufferCount != mBufferCount) ||
-                            (mServerBufferCount < minBufferCountNeeded));
-
-            if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
-                // wait for the FIFO to drain
-                mDequeueCondition.wait(mMutex);
-                // NOTE: we continue here because we need to reevaluate our
-                // whole state (eg: we could be abandoned or disconnected)
-                continue;
-            }
-
-            if (numberOfBuffersNeedsToChange) {
-                // here we're guaranteed that mQueue is empty
-                freeAllBuffersLocked();
-                mBufferCount = mServerBufferCount;
-                if (mBufferCount < minBufferCountNeeded)
-                    mBufferCount = minBufferCountNeeded;
-                mCurrentTexture = INVALID_BUFFER_SLOT;
-                returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
-            }
-
-            // look for a free buffer to give to the client
-            found = INVALID_BUFFER_SLOT;
-            foundSync = INVALID_BUFFER_SLOT;
-            dequeuedCount = 0;
-            for (int i = 0; i < mBufferCount; i++) {
-                const int state = mSlots[i].mBufferState;
-                if (state == BufferSlot::DEQUEUED) {
-                    dequeuedCount++;
-                }
-
-                // if buffer is FREE it CANNOT be current
-                ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
-                        "dequeueBuffer: buffer %d is both FREE and current!",
-                        i);
-
-                if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
-                    if (state == BufferSlot::FREE || i == mCurrentTexture) {
-                        foundSync = i;
-                        if (i != mCurrentTexture) {
-                            found = i;
-                            break;
-                        }
-                    }
-                } else {
-                    if (state == BufferSlot::FREE) {
-                        /* We return the oldest of the free buffers to avoid
-                         * stalling the producer if possible.  This is because
-                         * the consumer may still have pending reads of the
-                         * buffers in flight.
-                         */
-                        bool isOlder = mSlots[i].mFrameNumber <
-                                mSlots[found].mFrameNumber;
-                        if (found < 0 || isOlder) {
-                            foundSync = i;
-                            found = i;
-                        }
-                    }
-                }
-            }
-
-            // clients are not allowed to dequeue more than one buffer
-            // if they didn't set a buffer count.
-            if (!mClientBufferCount && dequeuedCount) {
-                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
-                        "setting the buffer count");
-                return -EINVAL;
-            }
-
-            // See whether a buffer has been queued since the last
-            // setBufferCount so we know whether to perform the
-            // MIN_UNDEQUEUED_BUFFERS check below.
-            bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
-            if (bufferHasBeenQueued) {
-                // make sure the client is not trying to dequeue more buffers
-                // than allowed.
-                const int avail = mBufferCount - (dequeuedCount+1);
-                if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
-                    ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
-                            "(dequeued=%d)",
-                            MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
-                            dequeuedCount);
-                    return -EBUSY;
-                }
-            }
-
-            // we're in synchronous mode and didn't find a buffer, we need to
-            // wait for some buffers to be consumed
-            tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
-            if (tryAgain) {
-                mDequeueCondition.wait(mMutex);
-            }
-        }
-
-        if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
-            // foundSync guaranteed to be != INVALID_BUFFER_SLOT
-            found = foundSync;
-        }
-
-        if (found == INVALID_BUFFER_SLOT) {
-            // This should not happen.
-            ST_LOGE("dequeueBuffer: no available buffer slots");
-            return -EBUSY;
-        }
-
-        const int buf = found;
-        *outBuf = found;
-
-        const bool useDefaultSize = !w && !h;
-        if (useDefaultSize) {
-            // use the default size
-            w = mDefaultWidth;
-            h = mDefaultHeight;
-        }
-
-        const bool updateFormat = (format != 0);
-        if (!updateFormat) {
-            // keep the current (or default) format
-            format = mPixelFormat;
-        }
-
-        // buffer is now in DEQUEUED (but can also be current at the same time,
-        // if we're in synchronous mode)
-        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
-
-        const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
-        if ((buffer == NULL) ||
-            (uint32_t(buffer->width)  != w) ||
-            (uint32_t(buffer->height) != h) ||
-            (uint32_t(buffer->format) != format) ||
-            ((uint32_t(buffer->usage) & usage) != usage))
-        {
-            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-            status_t error;
-            sp<GraphicBuffer> graphicBuffer(
-                    mGraphicBufferAlloc->createGraphicBuffer(
-                            w, h, format, usage, &error));
-            if (graphicBuffer == 0) {
-                ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
-                        "failed");
-                return error;
-            }
-            if (updateFormat) {
-                mPixelFormat = format;
-            }
-            mSlots[buf].mGraphicBuffer = graphicBuffer;
-            mSlots[buf].mRequestBufferCalled = false;
-            mSlots[buf].mFence = EGL_NO_SYNC_KHR;
-            if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
-                eglDestroyImageKHR(mSlots[buf].mEglDisplay,
-                        mSlots[buf].mEglImage);
-                mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
-                mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
-            }
-            if (mCurrentTexture == buf) {
-                // The current texture no longer references the buffer in this slot
-                // since we just allocated a new buffer.
-                mCurrentTexture = INVALID_BUFFER_SLOT;
-            }
-            returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
-        }
-
-        dpy = mSlots[buf].mEglDisplay;
-        fence = mSlots[buf].mFence;
-        mSlots[buf].mFence = EGL_NO_SYNC_KHR;
-    }
-
-    if (fence != EGL_NO_SYNC_KHR) {
-        EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
-        // If something goes wrong, log the error, but return the buffer without
-        // synchronizing access to it.  It's too late at this point to abort the
-        // dequeue operation.
-        if (result == EGL_FALSE) {
-            ALOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
-        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-            ALOGE("dequeueBuffer: timeout waiting for fence");
-        }
-        eglDestroySyncKHR(dpy, fence);
-    }
-
-    ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
-            mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
-
-    return returnFlags;
-}
-
-status_t SurfaceTexture::setSynchronousMode(bool enabled) {
-    ST_LOGV("setSynchronousMode: enabled=%d", enabled);
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
-        return NO_INIT;
-    }
-
-    status_t err = OK;
-    if (!mAllowSynchronousMode && enabled)
-        return err;
-
-    if (!enabled) {
-        // going to asynchronous mode, drain the queue
-        err = drainQueueLocked();
-        if (err != NO_ERROR)
-            return err;
-    }
-
-    if (mSynchronousMode != enabled) {
-        // - if we're going to asynchronous mode, the queue is guaranteed to be
-        // empty here
-        // - if the client set the number of buffers, we're guaranteed that
-        // we have at least 3 (because we don't allow less)
-        mSynchronousMode = enabled;
-        mDequeueCondition.signal();
-    }
-    return err;
-}
-
-status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
-        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
-    ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
-
-    sp<FrameAvailableListener> listener;
-
-    { // scope for the lock
-        Mutex::Autolock lock(mMutex);
-        if (mAbandoned) {
-            ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
-            return NO_INIT;
-        }
-        if (buf < 0 || buf >= mBufferCount) {
-            ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
-                    mBufferCount, buf);
-            return -EINVAL;
-        } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
-            ST_LOGE("queueBuffer: slot %d is not owned by the client "
-                    "(state=%d)", buf, mSlots[buf].mBufferState);
-            return -EINVAL;
-        } else if (buf == mCurrentTexture) {
-            ST_LOGE("queueBuffer: slot %d is current!", buf);
-            return -EINVAL;
-        } else if (!mSlots[buf].mRequestBufferCalled) {
-            ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
-                    "buffer", buf);
-            return -EINVAL;
-        }
-
-        if (mSynchronousMode) {
-            // In synchronous mode we queue all buffers in a FIFO.
-            mQueue.push_back(buf);
-
-            // Synchronous mode always signals that an additional frame should
-            // be consumed.
-            listener = mFrameAvailableListener;
-        } else {
-            // In asynchronous mode we only keep the most recent buffer.
-            if (mQueue.empty()) {
-                mQueue.push_back(buf);
-
-                // Asynchronous mode only signals that a frame should be
-                // consumed if no previous frame was pending. If a frame were
-                // pending then the consumer would have already been notified.
-                listener = mFrameAvailableListener;
-            } else {
-                Fifo::iterator front(mQueue.begin());
-                // buffer currently queued is freed
-                mSlots[*front].mBufferState = BufferSlot::FREE;
-                // and we record the new buffer index in the queued list
-                *front = buf;
-            }
-        }
-
-        mSlots[buf].mBufferState = BufferSlot::QUEUED;
-        mSlots[buf].mCrop = mNextCrop;
-        mSlots[buf].mTransform = mNextTransform;
-        mSlots[buf].mScalingMode = mNextScalingMode;
-        mSlots[buf].mTimestamp = timestamp;
-        mFrameCounter++;
-        mSlots[buf].mFrameNumber = mFrameCounter;
-
-        mDequeueCondition.signal();
-
-        *outWidth = mDefaultWidth;
-        *outHeight = mDefaultHeight;
-        *outTransform = 0;
-    } // scope for the lock
-
-    // call back without lock held
-    if (listener != 0) {
-        listener->onFrameAvailable();
-    }
-    return OK;
-}
-
-void SurfaceTexture::cancelBuffer(int buf) {
-    ST_LOGV("cancelBuffer: slot=%d", buf);
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        ST_LOGW("cancelBuffer: SurfaceTexture has been abandoned!");
-        return;
-    }
-
-    if (buf < 0 || buf >= mBufferCount) {
-        ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
-                mBufferCount, buf);
-        return;
-    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
-        ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
-                buf, mSlots[buf].mBufferState);
-        return;
-    }
-    mSlots[buf].mBufferState = BufferSlot::FREE;
-    mSlots[buf].mFrameNumber = 0;
-    mDequeueCondition.signal();
-}
-
-status_t SurfaceTexture::setCrop(const Rect& crop) {
-    ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
-            crop.bottom);
-
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        ST_LOGE("setCrop: SurfaceTexture has been abandoned!");
-        return NO_INIT;
-    }
-    mNextCrop = crop;
-    return OK;
-}
-
-status_t SurfaceTexture::setTransform(uint32_t transform) {
-    ST_LOGV("setTransform: xform=%#x", transform);
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        ST_LOGE("setTransform: SurfaceTexture has been abandoned!");
-        return NO_INIT;
-    }
-    mNextTransform = transform;
-    return OK;
-}
-
-status_t SurfaceTexture::connect(int api,
-        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
-    ST_LOGV("connect: api=%d", api);
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        ST_LOGE("connect: SurfaceTexture has been abandoned!");
-        return NO_INIT;
-    }
-
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-        case NATIVE_WINDOW_API_CPU:
-        case NATIVE_WINDOW_API_MEDIA:
-        case NATIVE_WINDOW_API_CAMERA:
-            if (mConnectedApi != NO_CONNECTED_API) {
-                ST_LOGE("connect: already connected (cur=%d, req=%d)",
-                        mConnectedApi, api);
-                err = -EINVAL;
-            } else {
-                mConnectedApi = api;
-                *outWidth = mDefaultWidth;
-                *outHeight = mDefaultHeight;
-                *outTransform = 0;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
-    }
-    return err;
-}
-
-status_t SurfaceTexture::disconnect(int api) {
-    ST_LOGV("disconnect: api=%d", api);
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        // it is not really an error to disconnect after the surface
-        // has been abandoned, it should just be a no-op.
-        return NO_ERROR;
-    }
-
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-        case NATIVE_WINDOW_API_CPU:
-        case NATIVE_WINDOW_API_MEDIA:
-        case NATIVE_WINDOW_API_CAMERA:
-            if (mConnectedApi == api) {
-                drainQueueAndFreeBuffersLocked();
-                mConnectedApi = NO_CONNECTED_API;
-                mNextCrop.makeInvalid();
-                mNextScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
-                mNextTransform = 0;
-                mDequeueCondition.signal();
-            } else {
-                ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
-                        mConnectedApi, api);
-                err = -EINVAL;
-            }
-            break;
-        default:
-            ST_LOGE("disconnect: unknown API %d", api);
-            err = -EINVAL;
-            break;
-    }
-    return err;
-}
-
-status_t SurfaceTexture::setScalingMode(int mode) {
-    ST_LOGV("setScalingMode: mode=%d", mode);
-
-    switch (mode) {
-        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
-        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
-            break;
-        default:
-            ST_LOGE("unknown scaling mode: %d", mode);
-            return BAD_VALUE;
-    }
-
-    Mutex::Autolock lock(mMutex);
-    mNextScalingMode = mode;
-    return OK;
-}
-
 status_t SurfaceTexture::updateTexImage() {
     ST_LOGV("updateTexImage");
     Mutex::Autolock lock(mMutex);
@@ -980,69 +375,6 @@
     mFrameAvailableListener = listener;
 }
 
-void SurfaceTexture::freeBufferLocked(int i) {
-    mSlots[i].mGraphicBuffer = 0;
-    mSlots[i].mBufferState = BufferSlot::FREE;
-    mSlots[i].mFrameNumber = 0;
-    if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
-        mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
-        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
-    }
-}
-
-void SurfaceTexture::freeAllBuffersLocked() {
-    ALOGW_IF(!mQueue.isEmpty(),
-            "freeAllBuffersLocked called but mQueue is not empty");
-    mCurrentTexture = INVALID_BUFFER_SLOT;
-    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        freeBufferLocked(i);
-    }
-}
-
-void SurfaceTexture::freeAllBuffersExceptHeadLocked() {
-    ALOGW_IF(!mQueue.isEmpty(),
-            "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
-    int head = -1;
-    if (!mQueue.empty()) {
-        Fifo::iterator front(mQueue.begin());
-        head = *front;
-    }
-    mCurrentTexture = INVALID_BUFFER_SLOT;
-    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (i != head) {
-            freeBufferLocked(i);
-        }
-    }
-}
-
-status_t SurfaceTexture::drainQueueLocked() {
-    while (mSynchronousMode && !mQueue.isEmpty()) {
-        mDequeueCondition.wait(mMutex);
-        if (mAbandoned) {
-            ST_LOGE("drainQueueLocked: SurfaceTexture has been abandoned!");
-            return NO_INIT;
-        }
-        if (mConnectedApi == NO_CONNECTED_API) {
-            ST_LOGE("drainQueueLocked: SurfaceTexture is not connected!");
-            return NO_INIT;
-        }
-    }
-    return NO_ERROR;
-}
-
-status_t SurfaceTexture::drainQueueAndFreeBuffersLocked() {
-    status_t err = drainQueueLocked();
-    if (err == NO_ERROR) {
-        if (mSynchronousMode) {
-            freeAllBuffersLocked();
-        } else {
-            freeAllBuffersExceptHeadLocked();
-        }
-    }
-    return err;
-}
-
 EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
         const sp<GraphicBuffer>& graphicBuffer) {
     EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 95e0a18..5ec3983 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -26,6 +26,7 @@
 		ShapeCache.cpp \
 		SkiaColorFilter.cpp \
 		SkiaShader.cpp \
+		Snapshot.cpp \
 		TextureCache.cpp \
 		TextDropShadowCache.cpp
 	
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index d1af1a3..0ef8469 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -55,6 +55,16 @@
 
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
 
+    if (extensions.hasDebugMarker()) {
+        eventMark = glInsertEventMarkerEXT;
+        startMark = glPushGroupMarkerEXT;
+        endMark = glPopGroupMarkerEXT;
+    } else {
+        eventMark = eventMarkNull;
+        startMark = startMarkNull;
+        endMark = endMarkNull;
+    }
+
     init();
 
     mDebugLevel = readDebugLevel();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 409584f..f8c7bcc 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -240,7 +240,15 @@
     GammaFontRenderer fontRenderer;
     ResourceCache resourceCache;
 
+    PFNGLINSERTEVENTMARKEREXTPROC eventMark;
+    PFNGLPUSHGROUPMARKEREXTPROC startMark;
+    PFNGLPOPGROUPMARKEREXTPROC endMark;
+
 private:
+    static void eventMarkNull(GLsizei length, const GLchar *marker) { }
+    static void startMarkNull(GLsizei length, const GLchar *marker) { }
+    static void endMarkNull() { }
+
     GLuint mCurrentBuffer;
     GLuint mCurrentIndicesBuffer;
     void* mCurrentPositionPointer;
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 0ad0c2a..16a3d73 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -62,6 +62,9 @@
 // Turn on to display debug info about the layer renderer
 #define DEBUG_LAYER_RENDERER 0
 
+// Turn on to enable additional debugging in the font renderers
+#define DEBUG_FONT_RENDERER 0
+
 // Turn on to dump display list state
 #define DEBUG_DISPLAY_LIST 0
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index ee935e4..1a11fbc 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -19,9 +19,10 @@
 
 #include "DisplayListLogBuffer.h"
 #include "DisplayListRenderer.h"
-#include <utils/String8.h>
 #include "Caches.h"
 
+#include <utils/String8.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -217,7 +218,7 @@
         indent[i] = ' ';
     }
     indent[count] = '\0';
-    ALOGD("%sStart display list (%p)", (char*) indent + 2, this);
+    ALOGD("%sStart display list (%p, %s)", (char*) indent + 2, this, mName.string());
 
     int saveCount = renderer.getSaveCount() - 1;
 
@@ -562,9 +563,11 @@
         indent[i] = ' ';
     }
     indent[count] = '\0';
-    DISPLAY_LIST_LOGD("%sStart display list (%p)", (char*) indent + 2, this);
+    DISPLAY_LIST_LOGD("%sStart display list (%p, %s)", (char*) indent + 2, this, mName.string());
 #endif
 
+    renderer.startMark(mName.string());
+
     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
     int saveCount = renderer.getSaveCount() - 1;
     while (!mReader.eof()) {
@@ -575,7 +578,9 @@
             case DrawGLFunction: {
                 Functor *functor = (Functor *) getInt();
                 DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
+                renderer.startMark("GL functor");
                 needsInvalidate |= renderer.callDrawGLFunction(functor, dirty);
+                renderer.endMark();
             }
             break;
             case Save: {
@@ -934,6 +939,8 @@
         }
     }
 
+    renderer.endMark();
+
     DISPLAY_LIST_LOGD("%sDone, returning %d", (char*) indent + 2, needsInvalidate);
     return needsInvalidate;
 }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 6fe4205..46506e4 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -28,6 +28,8 @@
 
 #include <cutils/compiler.h>
 
+#include <utils/String8.h>
+
 #include "DisplayListLogBuffer.h"
 #include "OpenGLRenderer.h"
 #include "utils/Functor.h"
@@ -128,6 +130,12 @@
         return mIsRenderable;
     }
 
+    void setName(const char* name) {
+        if (name) {
+            mName.setTo(name);
+        }
+    }
+
 private:
     void init();
 
@@ -224,6 +232,8 @@
     size_t mSize;
 
     bool mIsRenderable;
+
+    String8 mName;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 1069e3f..f11fecc 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -67,6 +67,7 @@
         mHasNPot = hasExtension("GL_OES_texture_npot");
         mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch");
         mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer");
+        mHasDebugMarker = hasExtension("GL_EXT_debug_marker");
 
         const char* vendor = (const char*) glGetString(GL_VENDOR);
         EXT_LOGD("Vendor: %s", vendor);
@@ -82,6 +83,7 @@
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
     inline bool needsHighpTexCoords() const { return mNeedsHighpTexCoords; }
     inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
+    inline bool hasDebugMarker() const { return mHasDebugMarker; }
 
     bool hasExtension(const char* extension) const {
         const String8 s(extension);
@@ -101,6 +103,7 @@
     bool mNeedsHighpTexCoords;
     bool mHasFramebufferFetch;
     bool mHasDiscardFramebuffer;
+    bool mHasDebugMarker;
 }; // class Extensions
 
 }; // namespace uirenderer
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 74efda2..3df105b 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -151,10 +151,12 @@
     int32_t bX = 0, bY = 0;
     for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
         for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
+#if DEBUG_FONT_RENDERER
             if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
                 ALOGE("Skipping invalid index");
                 continue;
             }
+#endif
             uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
             bitmap[bY * bitmapW + bX] = tempCol;
         }
@@ -226,7 +228,7 @@
     };
     RenderGlyph render = gRenderGlyph[mode];
 
-    if (positions == NULL) {
+    if (CC_LIKELY(positions == NULL)) {
         SkFixed prevRsbDelta = 0;
 
         float penX = x;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cc0e05e..afae70f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -124,9 +124,25 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// Debug
+///////////////////////////////////////////////////////////////////////////////
+
+void OpenGLRenderer::startMark(const char* name) const {
+    mCaches.startMark(0, name);
+}
+
+void OpenGLRenderer::endMark() const {
+    mCaches.endMark();
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // Setup
 ///////////////////////////////////////////////////////////////////////////////
 
+uint32_t OpenGLRenderer::getStencilSize() {
+    return STENCIL_BUFFER_SIZE;
+}
+
 void OpenGLRenderer::setViewport(int width, int height) {
     mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
 
@@ -738,7 +754,7 @@
 
     // TODO: See LayerRenderer.cpp::generateMesh() for important
     //       information about this implementation
-    if (!layer->region.isEmpty()) {
+    if (CC_LIKELY(!layer->region.isEmpty())) {
         size_t count;
         const android::Rect* rects = layer->region.getArray(&count);
 
@@ -1382,7 +1398,7 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    if (bitmap->getConfig() == SkBitmap::kA8_Config) {
+    if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
         drawAlphaBitmap(texture, left, top, paint);
     } else {
         drawTextureRect(left, top, right, bottom, texture, paint);
@@ -1438,9 +1454,9 @@
     float bottom = FLT_MIN;
 
 #if RENDER_LAYERS_AS_REGIONS
-    bool hasActiveLayer = hasLayer();
+    const bool hasActiveLayer = hasLayer();
 #else
-    bool hasActiveLayer = false;
+    const bool hasActiveLayer = false;
 #endif
 
     // TODO: Support the colors array
@@ -1525,7 +1541,7 @@
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
-    if (mSnapshot->transform->isPureTranslate()) {
+    if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
         const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f);
         const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -1571,7 +1587,7 @@
     const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
             right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
 
-    if (mesh && mesh->verticesCount > 0) {
+    if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
         const bool pureTranslate = mSnapshot->transform->isPureTranslate();
 #if RENDER_LAYERS_AS_REGIONS
         // Mark the current layer dirty where we are going to draw the patch
@@ -1581,7 +1597,7 @@
             const size_t count = mesh->quads.size();
             for (size_t i = 0; i < count; i++) {
                 const Rect& bounds = mesh->quads.itemAt(i);
-                if (pureTranslate) {
+                if (CC_LIKELY(pureTranslate)) {
                     const float x = (int) floorf(bounds.left + offsetX + 0.5f);
                     const float y = (int) floorf(bounds.top + offsetY + 0.5f);
                     dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
@@ -1593,7 +1609,7 @@
         }
 #endif
 
-        if (pureTranslate) {
+        if (CC_LIKELY(pureTranslate)) {
             const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
             const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -1621,7 +1637,7 @@
     float inverseScaleX = 1.0f;
     float inverseScaleY = 1.0f;
     // The quad that we use needs to account for scaling.
-    if (!mSnapshot->transform->isPureTranslate()) {
+    if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
         Matrix4 *mat = mSnapshot->transform;
         float m00 = mat->data[Matrix4::kScaleX];
         float m01 = mat->data[Matrix4::kSkewY];
@@ -1727,7 +1743,7 @@
         // The quad that we use for AA and hairlines needs to account for scaling. For hairlines
         // the line on the screen should always be one pixel wide regardless of scale. For
         // AA lines, we only want one pixel of translucent boundary around the quad.
-        if (!mSnapshot->transform->isPureTranslate()) {
+        if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
             Matrix4 *mat = mSnapshot->transform;
             float m00 = mat->data[Matrix4::kScaleX];
             float m01 = mat->data[Matrix4::kSkewY];
@@ -1735,8 +1751,8 @@
             float m10 = mat->data[Matrix4::kSkewX];
             float m11 = mat->data[Matrix4::kScaleX];
             float m12 = mat->data[6];
-            float scaleX = sqrt(m00*m00 + m01*m01);
-            float scaleY = sqrt(m10*m10 + m11*m11);
+            float scaleX = sqrtf(m00 * m00 + m01 * m01);
+            float scaleY = sqrtf(m10 * m10 + m11 * m11);
             inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
             inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0;
             if (inverseScaleX != 1.0f || inverseScaleY != 1.0f) {
@@ -1754,11 +1770,7 @@
     setupDrawColor(paint->getColor(), alpha);
     setupDrawColorFilter();
     setupDrawShader();
-    if (isAA) {
-        setupDrawBlending(true, mode);
-    } else {
-        setupDrawBlending(mode);
-    }
+    setupDrawBlending(isAA, mode);
     setupDrawProgram();
     setupDrawModelViewIdentity(true);
     setupDrawColorUniforms();
@@ -1776,7 +1788,7 @@
     Vertex* vertices = &lines[0];
     AAVertex wLines[verticesCount];
     AAVertex* aaVertices = &wLines[0];
-    if (!isAA) {
+    if (CC_UNLIKELY(!isAA)) {
         setupDrawVertices(vertices);
     } else {
         void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
@@ -2136,9 +2148,9 @@
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
 #if RENDER_LAYERS_AS_REGIONS
-    bool hasActiveLayer = hasLayer();
+    const bool hasActiveLayer = hasLayer();
 #else
-    bool hasActiveLayer = false;
+    const bool hasActiveLayer = false;
 #endif
 
     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
@@ -2185,7 +2197,7 @@
     const float oldX = x;
     const float oldY = y;
     const bool pureTranslate = mSnapshot->transform->isPureTranslate();
-    if (pureTranslate) {
+    if (CC_LIKELY(pureTranslate)) {
         x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
         y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
     }
@@ -2202,7 +2214,7 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    if (mHasShadow) {
+    if (CC_UNLIKELY(mHasShadow)) {
         mCaches.activeTexture(0);
 
         mCaches.dropShadowCache.setFontRenderer(fontRenderer);
@@ -2261,9 +2273,9 @@
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
 #if RENDER_LAYERS_AS_REGIONS
-    bool hasActiveLayer = hasLayer();
+    const bool hasActiveLayer = hasLayer();
 #else
-    bool hasActiveLayer = false;
+    const bool hasActiveLayer = false;
 #endif
 
     if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
@@ -2310,7 +2322,7 @@
     layer->setAlpha(alpha, mode);
 
 #if RENDER_LAYERS_AS_REGIONS
-    if (!layer->region.isEmpty()) {
+    if (CC_LIKELY(!layer->region.isEmpty())) {
         if (layer->region.isRect()) {
             composeLayerRect(layer, layer->regionRect);
         } else if (layer->mesh) {
@@ -2326,7 +2338,7 @@
             setupDrawPureColorUniforms();
             setupDrawColorFilterUniforms();
             setupDrawTexture(layer->getTexture());
-            if (mSnapshot->transform->isPureTranslate()) {
+            if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
                 x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
                 y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -2486,7 +2498,7 @@
                 break;
         }
 
-        if (underlineWidth > 0.0f) {
+        if (CC_LIKELY(underlineWidth > 0.0f)) {
             const float textSize = paintCopy.getTextSize();
             const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
 
@@ -2555,7 +2567,7 @@
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
-    if (mSnapshot->transform->isPureTranslate()) {
+    if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
         const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
         const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
 
@@ -2615,8 +2627,8 @@
         // the blending, turn blending off here
         // If the blend mode cannot be implemented using shaders, fall
         // back to the default SrcOver blend mode instead
-        if (mode > SkXfermode::kScreen_Mode) {
-            if (mCaches.extensions.hasFramebufferFetch()) {
+        if CC_UNLIKELY((mode > SkXfermode::kScreen_Mode)) {
+            if (CC_UNLIKELY(mCaches.extensions.hasFramebufferFetch())) {
                 description.framebufferMode = mode;
                 description.swapSrcDst = swapSrcDst;
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index ae355bb..3c2d09e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -141,6 +141,11 @@
 
     SkPaint* filterPaint(SkPaint* paint);
 
+    ANDROID_API static uint32_t getStencilSize();
+
+    void startMark(const char* name) const;
+    void endMark() const;
+
 protected:
     /**
      * Compose the layer defined in the current snapshot with the layer
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 2eae0f1..7854729 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -37,6 +37,11 @@
 // Textures used by layers must have dimensions multiples of this number
 #define LAYER_SIZE 64
 
+// Defines the size in bits of the stencil buffer
+// Note: Only 1 bit is required for clipping but more bits are required
+// to properly implement the winding fill rule when rasterizing paths
+#define STENCIL_BUFFER_SIZE 0
+
 /**
  * Debug level for app developers.
  */
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
new file mode 100644
index 0000000..de2c674
--- /dev/null
+++ b/libs/hwui/Snapshot.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "Snapshot.h"
+
+#include <SkCanvas.h>
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors
+///////////////////////////////////////////////////////////////////////////////
+
+Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
+        invisible(false), empty(false) {
+
+    transform = &mTransformRoot;
+    clipRect = &mClipRectRoot;
+    region = NULL;
+    clipRegion = NULL;
+}
+
+/**
+ * Copies the specified snapshot/ The specified snapshot is stored as
+ * the previous snapshot.
+ */
+Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
+        flags(0), previous(s), layer(NULL), fbo(s->fbo),
+        invisible(s->invisible), empty(false),
+        viewport(s->viewport), height(s->height) {
+
+    clipRegion = NULL;
+
+    if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
+        mTransformRoot.load(*s->transform);
+        transform = &mTransformRoot;
+    } else {
+        transform = s->transform;
+    }
+
+    if (saveFlags & SkCanvas::kClip_SaveFlag) {
+        mClipRectRoot.set(*s->clipRect);
+        clipRect = &mClipRectRoot;
+#if STENCIL_BUFFER_SIZE
+        if (s->clipRegion) {
+            mClipRegionRoot.merge(*s->clipRegion);
+            clipRegion = &mClipRegionRoot;
+        }
+#endif
+    } else {
+        clipRect = s->clipRect;
+#if STENCIL_BUFFER_SIZE
+        clipRegion = s->clipRegion;
+#endif
+    }
+
+    if (s->flags & Snapshot::kFlagFboTarget) {
+        flags |= Snapshot::kFlagFboTarget;
+        region = s->region;
+    } else {
+        region = NULL;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Clipping
+///////////////////////////////////////////////////////////////////////////////
+
+void Snapshot::ensureClipRegion() {
+#if STENCIL_BUFFER_SIZE
+    if (!clipRegion) {
+        clipRegion = &mClipRegionRoot;
+        android::Rect tmp(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+        clipRegion->set(tmp);
+    }
+#endif
+}
+
+void Snapshot::copyClipRectFromRegion() {
+#if STENCIL_BUFFER_SIZE
+    if (!clipRegion->isEmpty()) {
+        android::Rect bounds(clipRegion->bounds());
+        clipRect->set(bounds.left, bounds.top, bounds.right, bounds.bottom);
+
+        if (clipRegion->isRect()) {
+            clipRegion->clear();
+            clipRegion = NULL;
+        }
+    } else {
+        clipRect->setEmpty();
+        clipRegion = NULL;
+    }
+#endif
+}
+
+bool Snapshot::clipRegionOr(float left, float top, float right, float bottom) {
+#if STENCIL_BUFFER_SIZE
+    android::Rect tmp(left, top, right, bottom);
+    clipRegion->orSelf(tmp);
+    copyClipRectFromRegion();
+    return true;
+#else
+    return false;
+#endif
+}
+
+bool Snapshot::clipRegionXor(float left, float top, float right, float bottom) {
+#if STENCIL_BUFFER_SIZE
+    android::Rect tmp(left, top, right, bottom);
+    clipRegion->xorSelf(tmp);
+    copyClipRectFromRegion();
+    return true;
+#else
+    return false;
+#endif
+}
+
+bool Snapshot::clipRegionAnd(float left, float top, float right, float bottom) {
+#if STENCIL_BUFFER_SIZE
+    android::Rect tmp(left, top, right, bottom);
+    clipRegion->andSelf(tmp);
+    copyClipRectFromRegion();
+    return true;
+#else
+    return false;
+#endif
+}
+
+bool Snapshot::clipRegionNand(float left, float top, float right, float bottom) {
+#if STENCIL_BUFFER_SIZE
+    android::Rect tmp(left, top, right, bottom);
+    clipRegion->subtractSelf(tmp);
+    copyClipRectFromRegion();
+    return true;
+#else
+    return false;
+#endif
+}
+
+bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
+    Rect r(left, top, right, bottom);
+    transform->mapRect(r);
+    return clipTransformed(r, op);
+}
+
+bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
+    bool clipped = false;
+
+    switch (op) {
+        case SkRegion::kDifference_Op: {
+            ensureClipRegion();
+            clipped = clipRegionNand(r.left, r.top, r.right, r.bottom);
+            break;
+        }
+        case SkRegion::kIntersect_Op: {
+            if (CC_UNLIKELY(clipRegion)) {
+                clipped = clipRegionOr(r.left, r.top, r.right, r.bottom);
+            } else {
+                clipped = clipRect->intersect(r);
+                if (!clipped) {
+                    clipRect->setEmpty();
+                    clipped = true;
+                }
+            }
+            break;
+        }
+        case SkRegion::kUnion_Op: {
+            if (CC_UNLIKELY(clipRegion)) {
+                clipped = clipRegionAnd(r.left, r.top, r.right, r.bottom);
+            } else {
+                clipped = clipRect->unionWith(r);
+            }
+            break;
+        }
+        case SkRegion::kXOR_Op: {
+            ensureClipRegion();
+            clipped = clipRegionXor(r.left, r.top, r.right, r.bottom);
+            break;
+        }
+        case SkRegion::kReverseDifference_Op: {
+            // TODO!!!!!!!
+            break;
+        }
+        case SkRegion::kReplace_Op: {
+            setClip(r.left, r.top, r.right, r.bottom);
+            clipped = true;
+            break;
+        }
+    }
+
+    if (clipped) {
+        flags |= Snapshot::kFlagClipSet;
+    }
+
+    return clipped;
+}
+
+void Snapshot::setClip(float left, float top, float right, float bottom) {
+    clipRect->set(left, top, right, bottom);
+#if STENCIL_BUFFER_SIZE
+    if (clipRegion) {
+        clipRegion->clear();
+        clipRegion = NULL;
+    }
+#endif
+    flags |= Snapshot::kFlagClipSet;
+}
+
+const Rect& Snapshot::getLocalClip() {
+    mat4 inverse;
+    inverse.loadInverse(*transform);
+
+    mLocalClip.set(*clipRect);
+    inverse.mapRect(mLocalClip);
+
+    return mLocalClip;
+}
+
+void Snapshot::resetClip(float left, float top, float right, float bottom) {
+    clipRect = &mClipRectRoot;
+    setClip(left, top, right, bottom);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Transforms
+///////////////////////////////////////////////////////////////////////////////
+
+void Snapshot::resetTransform(float x, float y, float z) {
+    transform = &mTransformRoot;
+    transform->loadTranslate(x, y, z);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Queries
+///////////////////////////////////////////////////////////////////////////////
+
+bool Snapshot::isIgnored() const {
+    return invisible || empty;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index aff7b93..b2bc879 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -23,7 +23,7 @@
 #include <utils/RefBase.h>
 #include <ui/Region.h>
 
-#include <SkCanvas.h>
+#include <SkRegion.h>
 
 #include "Layer.h"
 #include "Matrix.h"
@@ -43,43 +43,12 @@
  */
 class Snapshot: public LightRefBase<Snapshot> {
 public:
-    Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false), empty(false) {
-        transform = &mTransformRoot;
-        clipRect = &mClipRectRoot;
-        region = NULL;
-    }
+
+    Snapshot();
+    Snapshot(const sp<Snapshot>& s, int saveFlags);
 
     /**
-     * Copies the specified snapshot/ The specified snapshot is stored as
-     * the previous snapshot.
-     */
-    Snapshot(const sp<Snapshot>& s, int saveFlags):
-            flags(0), previous(s), layer(NULL), fbo(s->fbo),
-            invisible(s->invisible), empty(false), viewport(s->viewport), height(s->height) {
-        if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
-            mTransformRoot.load(*s->transform);
-            transform = &mTransformRoot;
-        } else {
-            transform = s->transform;
-        }
-
-        if (saveFlags & SkCanvas::kClip_SaveFlag) {
-            mClipRectRoot.set(*s->clipRect);
-            clipRect = &mClipRectRoot;
-        } else {
-            clipRect = s->clipRect;
-        }
-
-        if (s->flags & Snapshot::kFlagFboTarget) {
-            flags |= Snapshot::kFlagFboTarget;
-            region = s->region;
-        } else {
-            region = NULL;
-        }
-    }
-
-    /**
-     * Various flags set on #flags.
+     * Various flags set on ::flags.
      */
     enum Flags {
         /**
@@ -115,87 +84,41 @@
      * by this snapshot's trasnformation.
      */
     bool clip(float left, float top, float right, float bottom,
-            SkRegion::Op op = SkRegion::kIntersect_Op) {
-        Rect r(left, top, right, bottom);
-        transform->mapRect(r);
-        return clipTransformed(r, op);
-    }
+            SkRegion::Op op = SkRegion::kIntersect_Op);
 
     /**
      * Modifies the current clip with the new clip rectangle and
      * the specified operation. The specified rectangle is considered
      * already transformed.
      */
-    bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op) {
-        bool clipped = false;
-
-        // NOTE: The unimplemented operations require support for regions
-        // Supporting regions would require using a stencil buffer instead
-        // of the scissor. The stencil buffer itself is not too expensive
-        // (memory cost excluded) but on fillrate limited devices, managing
-        // the stencil might have a negative impact on the framerate.
-        switch (op) {
-            case SkRegion::kDifference_Op:
-                break;
-            case SkRegion::kIntersect_Op:
-                clipped = clipRect->intersect(r);
-                if (!clipped) {
-                    clipRect->setEmpty();
-                    clipped = true;
-                }
-                break;
-            case SkRegion::kUnion_Op:
-                clipped = clipRect->unionWith(r);
-                break;
-            case SkRegion::kXOR_Op:
-                break;
-            case SkRegion::kReverseDifference_Op:
-                break;
-            case SkRegion::kReplace_Op:
-                clipRect->set(r);
-                clipped = true;
-                break;
-        }
-
-        if (clipped) {
-            flags |= Snapshot::kFlagClipSet;
-        }
-
-        return clipped;
-    }
+    bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
 
     /**
      * Sets the current clip.
      */
-    void setClip(float left, float top, float right, float bottom) {
-        clipRect->set(left, top, right, bottom);
-        flags |= Snapshot::kFlagClipSet;
-    }
+    void setClip(float left, float top, float right, float bottom);
 
-    const Rect& getLocalClip() {
-        mat4 inverse;
-        inverse.loadInverse(*transform);
+    /**
+     * Returns the current clip in local coordinates. The clip rect is
+     * transformed by the inverse transform matrix.
+     */
+    const Rect& getLocalClip();
 
-        mLocalClip.set(*clipRect);
-        inverse.mapRect(mLocalClip);
+    /**
+     * Resets the clip to the specified rect.
+     */
+    void resetClip(float left, float top, float right, float bottom);
 
-        return mLocalClip;
-    }
+    /**
+     * Resets the current transform to a pure 3D translation.
+     */
+    void resetTransform(float x, float y, float z);
 
-    void resetTransform(float x, float y, float z) {
-        transform = &mTransformRoot;
-        transform->loadTranslate(x, y, z);
-    }
-
-    void resetClip(float left, float top, float right, float bottom) {
-        clipRect = &mClipRectRoot;
-        clipRect->set(left, top, right, bottom);
-        flags |= Snapshot::kFlagClipSet;
-    }
-
-    bool isIgnored() const {
-        return invisible || empty;
-    }
+    /**
+     * Indicates whether this snapshot should be ignored. A snapshot
+     * is typicalled ignored if its layer is invisible or empty.
+     */
+    bool isIgnored() const;
 
     /**
      * Dirty flags.
@@ -209,6 +132,8 @@
 
     /**
      * Only set when the flag kFlagIsLayer is set.
+     *
+     * This snapshot does not own the layer, this pointer must not be freed.
      */
     Layer* layer;
 
@@ -249,25 +174,57 @@
     /**
      * Local transformation. Holds the current translation, scale and
      * rotation values.
+     *
+     * This is a reference to a matrix owned by this snapshot or another
+     *  snapshot. This pointer must not be freed. See ::mTransformRoot.
      */
     mat4* transform;
 
     /**
-     * Current clip region. The clip is stored in canvas-space coordinates,
+     * Current clip rect. The clip is stored in canvas-space coordinates,
      * (screen-space coordinates in the regular case.)
+     *
+     * This is a reference to a rect owned by this snapshot or another
+     * snapshot. This pointer must not be freed. See ::mClipRectRoot.
      */
     Rect* clipRect;
 
     /**
+     * Current clip region. The clip is stored in canvas-space coordinates,
+     * (screen-space coordinates in the regular case.)
+     *
+     * This is a reference to a region owned by this snapshot or another
+     * snapshot. This pointer must not be freed. See ::mClipRegionRoot.
+     *
+     * This field is used only if STENCIL_BUFFER_SIZE is > 0.
+     */
+    Region* clipRegion;
+
+    /**
      * The ancestor layer's dirty region.
+     *
+     * This is a reference to a region owned by a layer. This pointer must
+     * not be freed.
      */
     Region* region;
 
 private:
+    void ensureClipRegion();
+    void copyClipRectFromRegion();
+
+    bool clipRegionOr(float left, float top, float right, float bottom);
+    bool clipRegionXor(float left, float top, float right, float bottom);
+    bool clipRegionAnd(float left, float top, float right, float bottom);
+    bool clipRegionNand(float left, float top, float right, float bottom);
+
     mat4 mTransformRoot;
     Rect mClipRectRoot;
     Rect mLocalClip;
 
+#if STENCIL_BUFFER_SIZE
+    Region mClipRegionRoot;
+#endif
+
 }; // class Snapshot
 
 }; // namespace uirenderer
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 58d3e5c..9c5d06b 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -89,13 +89,13 @@
 	rsFifoSocket.cpp \
 	rsFileA3D.cpp \
 	rsFont.cpp \
-	rsLocklessFifo.cpp \
 	rsObjectBase.cpp \
 	rsMatrix2x2.cpp \
 	rsMatrix3x3.cpp \
 	rsMatrix4x4.cpp \
 	rsMesh.cpp \
 	rsMutex.cpp \
+	rsPath.cpp \
 	rsProgram.cpp \
 	rsProgramFragment.cpp \
 	rsProgramStore.cpp \
@@ -118,6 +118,7 @@
 	driver/rsdGL.cpp \
 	driver/rsdMesh.cpp \
 	driver/rsdMeshObj.cpp \
+	driver/rsdPath.cpp \
 	driver/rsdProgram.cpp \
 	driver/rsdProgramRaster.cpp \
 	driver/rsdProgramStore.cpp \
@@ -128,7 +129,7 @@
 	driver/rsdShaderCache.cpp \
 	driver/rsdVertexArray.cpp
 
-LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc libbcinfo
+LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc libbcinfo libgui
 
 LOCAL_STATIC_LIBRARIES := libdex libft2
 
@@ -196,13 +197,13 @@
 	rsFifoSocket.cpp \
 	rsFileA3D.cpp \
 	rsFont.cpp \
-	rsLocklessFifo.cpp \
 	rsObjectBase.cpp \
 	rsMatrix2x2.cpp \
 	rsMatrix3x3.cpp \
 	rsMatrix4x4.cpp \
 	rsMesh.cpp \
 	rsMutex.cpp \
+	rsPath.cpp \
 	rsProgram.cpp \
 	rsProgramFragment.cpp \
 	rsProgramStore.cpp \
diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/RenderScriptDefines.h
index d092520..990ef26 100644
--- a/libs/rs/RenderScriptDefines.h
+++ b/libs/rs/RenderScriptDefines.h
@@ -41,6 +41,7 @@
 typedef void * RsSampler;
 typedef void * RsScript;
 typedef void * RsMesh;
+typedef void * RsPath;
 typedef void * RsType;
 typedef void * RsObjectBase;
 
@@ -99,8 +100,11 @@
     RS_ALLOCATION_USAGE_GRAPHICS_VERTEX = 0x0004,
     RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS = 0x0008,
     RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET = 0x0010,
+    RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020,
+    RS_ALLOCATION_USAGE_IO_INPUT = 0x0040,
+    RS_ALLOCATION_USAGE_IO_OUTPUT = 0x0080,
 
-    RS_ALLOCATION_USAGE_ALL = 0x000F
+    RS_ALLOCATION_USAGE_ALL = 0x00FF
 };
 
 enum RsAllocationMipmapControl {
@@ -152,6 +156,8 @@
     RS_TYPE_PROGRAM_VERTEX,
     RS_TYPE_PROGRAM_RASTER,
     RS_TYPE_PROGRAM_STORE,
+
+    RS_TYPE_INVALID = 10000,
 };
 
 enum RsDataKind {
@@ -163,6 +169,8 @@
     RS_KIND_PIXEL_RGB,
     RS_KIND_PIXEL_RGBA,
     RS_KIND_PIXEL_DEPTH,
+
+    RS_KIND_INVALID = 100,
 };
 
 enum RsSamplerParam {
@@ -181,6 +189,8 @@
     RS_SAMPLER_WRAP,
     RS_SAMPLER_CLAMP,
     RS_SAMPLER_LINEAR_MIP_NEAREST,
+
+    RS_SAMPLER_INVALID = 100,
 };
 
 enum RsTextureTarget {
@@ -221,7 +231,8 @@
     RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,   // 5
     RS_BLEND_SRC_DST_ALPHA,             // 6
     RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,   // 7
-    RS_BLEND_SRC_SRC_ALPHA_SATURATE     // 8
+    RS_BLEND_SRC_SRC_ALPHA_SATURATE,    // 8
+    RS_BLEND_SRC_INVALID = 100,
 };
 
 enum RsBlendDstFunc {
@@ -232,7 +243,9 @@
     RS_BLEND_DST_SRC_ALPHA,             // 4
     RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,   // 5
     RS_BLEND_DST_DST_ALPHA,             // 6
-    RS_BLEND_DST_ONE_MINUS_DST_ALPHA    // 7
+    RS_BLEND_DST_ONE_MINUS_DST_ALPHA,   // 7
+
+    RS_BLEND_DST_INVALID = 100,
 };
 
 enum RsTexEnvMode {
@@ -255,7 +268,14 @@
     RS_PRIMITIVE_LINE_STRIP,
     RS_PRIMITIVE_TRIANGLE,
     RS_PRIMITIVE_TRIANGLE_STRIP,
-    RS_PRIMITIVE_TRIANGLE_FAN
+    RS_PRIMITIVE_TRIANGLE_FAN,
+
+    RS_PRIMITIVE_INVALID = 100,
+};
+
+enum RsPathPrimitive {
+    RS_PATH_PRIMITIVE_QUADRATIC_BEZIER,
+    RS_PATH_PRIMITIVE_CUBIC_BEZIER
 };
 
 enum RsError {
@@ -309,7 +329,8 @@
 enum RsCullMode {
     RS_CULL_BACK,
     RS_CULL_FRONT,
-    RS_CULL_NONE
+    RS_CULL_NONE,
+    RS_CULL_INVALID = 100,
 };
 
 typedef struct {
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index 1f70e66..ea92192 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -134,6 +134,13 @@
 static void UploadToTexture(const Context *rsc, const Allocation *alloc) {
     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
 
+    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) {
+        if (!drv->textureID) {
+            RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
+        }
+        return;
+    }
+
     if (!drv->glType || !drv->glFormat) {
         return;
     }
@@ -212,10 +219,13 @@
         return false;
     }
 
-    void * ptr = malloc(alloc->mHal.state.type->getSizeBytes());
+    void * ptr = alloc->mHal.state.usrPtr;
     if (!ptr) {
-        free(drv);
-        return false;
+        ptr = malloc(alloc->mHal.state.type->getSizeBytes());
+        if (!ptr) {
+            free(drv);
+            return false;
+        }
     }
 
     drv->glTarget = GL_NONE;
@@ -269,7 +279,7 @@
         drv->renderTargetID = 0;
     }
 
-    if (drv->mallocPtr) {
+    if (drv->mallocPtr && !alloc->mHal.state.usrPtr) {
         free(drv->mallocPtr);
         drv->mallocPtr = NULL;
     }
@@ -370,6 +380,12 @@
     drv->uploadDeferred = true;
 }
 
+int32_t rsdAllocationInitSurfaceTexture(const Context *rsc, const Allocation *alloc) {
+    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
+    UploadToTexture(rsc, alloc);
+    return drv->textureID;
+}
+
 void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
                          uint32_t xoff, uint32_t lod, uint32_t count,
                          const void *data, uint32_t sizeBytes) {
diff --git a/libs/rs/driver/rsdAllocation.h b/libs/rs/driver/rsdAllocation.h
index 4fc4419..230804b 100644
--- a/libs/rs/driver/rsdAllocation.h
+++ b/libs/rs/driver/rsdAllocation.h
@@ -67,6 +67,8 @@
                           RsAllocationUsageType src);
 void rsdAllocationMarkDirty(const android::renderscript::Context *rsc,
                             const android::renderscript::Allocation *alloc);
+int32_t rsdAllocationInitSurfaceTexture(const android::renderscript::Context *rsc,
+                                        const android::renderscript::Allocation *alloc);
 
 void rsdAllocationData1D(const android::renderscript::Context *rsc,
                          const android::renderscript::Allocation *alloc,
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 1a535d0..e011955 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -18,6 +18,7 @@
 #include "rsdAllocation.h"
 #include "rsdBcc.h"
 #include "rsdGL.h"
+#include "rsdPath.h"
 #include "rsdProgramStore.h"
 #include "rsdProgramRaster.h"
 #include "rsdProgramVertex.h"
@@ -72,6 +73,7 @@
         rsdAllocationResize,
         rsdAllocationSyncAll,
         rsdAllocationMarkDirty,
+        rsdAllocationInitSurfaceTexture,
         rsdAllocationData1D,
         rsdAllocationData2D,
         rsdAllocationData3D,
@@ -114,6 +116,13 @@
     },
 
     {
+        rsdPathInitStatic,
+        rsdPathInitDynamic,
+        rsdPathDraw,
+        rsdPathDestroy
+    },
+
+    {
         rsdSamplerInit,
         rsdSamplerDestroy
     },
@@ -259,6 +268,9 @@
     for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
         setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority);
     }
+    if (dc->mHasGraphics) {
+        rsdGLSetPriority(rsc, priority);
+    }
 }
 
 void Shutdown(Context *rsc) {
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
index 126c87a..168bdf3 100644
--- a/libs/rs/driver/rsdCore.h
+++ b/libs/rs/driver/rsdCore.h
@@ -41,6 +41,7 @@
 typedef struct RsdHalRec {
     uint32_t version_major;
     uint32_t version_minor;
+    bool mHasGraphics;
 
     struct Workers {
         volatile int mRunningCount;
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index b53a68cf..b136cc7 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -215,6 +215,8 @@
     ret = eglChooseConfig(dc->gl.egl.display, configAttribs, 0, 0, &numConfigs);
     checkEglError("eglGetConfigs", ret);
 
+    eglSwapInterval(dc->gl.egl.display, 0);
+
     if (numConfigs) {
         EGLConfig* const configs = new EGLConfig[numConfigs];
 
@@ -340,9 +342,9 @@
 
     dc->gl.gl.OES_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
                                                 "GL_OES_texture_npot");
-    dc->gl.gl.GL_IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
+    dc->gl.gl.IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
                                                    "GL_IMG_texture_npot");
-    dc->gl.gl.GL_NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions,
+    dc->gl.gl.NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions,
                                                             "GL_NV_texture_npot_2D_mipmap");
     dc->gl.gl.EXT_texture_max_aniso = 1.0f;
     bool hasAniso = NULL != strstr((const char *)dc->gl.gl.extensions,
@@ -359,6 +361,7 @@
     dc->gl.vertexArrayState = new RsdVertexArrayState();
     dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
     dc->gl.currentFrameBuffer = NULL;
+    dc->mHasGraphics = true;
 
     ALOGV("%p initGLThread end", rsc);
     rsc->setWatchdogGL(NULL, 0, NULL);
@@ -419,6 +422,15 @@
     RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
 }
 
+void rsdGLSetPriority(const Context *rsc, int32_t priority) {
+    if (priority > 0) {
+        // Mark context as low priority.
+        ALOGV("low pri");
+    } else {
+        ALOGV("normal pri");
+    }
+}
+
 void rsdGLCheckError(const android::renderscript::Context *rsc,
                      const char *msg, bool isFatal) {
     GLenum err = glGetError();
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index fc33885..e015cb1 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -61,8 +61,8 @@
         int32_t maxVertexTextureUnits;
 
         bool OES_texture_npot;
-        bool GL_IMG_texture_npot;
-        bool GL_NV_texture_npot_2D_mipmap;
+        bool IMG_texture_npot;
+        bool NV_texture_npot_2D_mipmap;
         float EXT_texture_max_aniso;
     } gl;
 
@@ -82,6 +82,8 @@
 void rsdGLSwap(const android::renderscript::Context *rsc);
 void rsdGLCheckError(const android::renderscript::Context *rsc,
                      const char *msg, bool isFatal = false);
+void rsdGLSetPriority(const android::renderscript::Context *rsc,
+                      int32_t priority);
 
 #endif
 
diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp
index eb62ddb..50daf3e 100644
--- a/libs/rs/driver/rsdMesh.cpp
+++ b/libs/rs/driver/rsdMesh.cpp
@@ -35,7 +35,7 @@
     }
     drv = new RsdMeshObj(rsc, m);
     m->mHal.drv = drv;
-    return drv->init();
+    return drv->init(rsc);
 }
 
 void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) {
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
index 99d79dc..893f046 100644
--- a/libs/rs/driver/rsdMeshObj.cpp
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -50,14 +50,9 @@
 }
 
 bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
-    // Do not create attribs for padding
-    if (elem->getFieldName(fieldIdx)[0] == '#') {
-        return false;
-    }
-
     // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
     // Filter rs types accordingly
-    RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
+    RsDataType dt = elem->mHal.state.fields[fieldIdx]->mHal.state.dataType;
     if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
         dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
         dt != RS_TYPE_SIGNED_16) {
@@ -65,7 +60,7 @@
     }
 
     // Now make sure they are not arrays
-    uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
+    uint32_t arraySize = elem->mHal.state.fieldArraySizes[fieldIdx];
     if (arraySize != 1) {
         return false;
     }
@@ -73,15 +68,15 @@
     return true;
 }
 
-bool RsdMeshObj::init() {
+bool RsdMeshObj::init(const Context *rsc) {
 
-    updateGLPrimitives();
+    updateGLPrimitives(rsc);
 
     // Count the number of gl attrs to initialize
     mAttribCount = 0;
     for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
         const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
-        for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
+        for (uint32_t ct=0; ct < elem->mHal.state.fieldsCount; ct++) {
             if (isValidGLComponent(elem, ct)) {
                 mAttribCount ++;
             }
@@ -104,21 +99,21 @@
     uint32_t userNum = 0;
     for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
         const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
-        uint32_t stride = elem->getSizeBytes();
-        for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
-            const Component &c = elem->getField(fieldI)->getComponent();
+        uint32_t stride = elem->mHal.state.elementSizeBytes;
+        for (uint32_t fieldI=0; fieldI < elem->mHal.state.fieldsCount; fieldI++) {
+            const Element *f = elem->mHal.state.fields[fieldI];
 
             if (!isValidGLComponent(elem, fieldI)) {
                 continue;
             }
 
-            mAttribs[userNum].size = c.getVectorSize();
-            mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
-            mAttribs[userNum].type = rsdTypeToGLType(c.getType());
-            mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+            mAttribs[userNum].size = f->mHal.state.vectorSize;
+            mAttribs[userNum].offset = elem->mHal.state.fieldOffsetBytes[fieldI];
+            mAttribs[userNum].type = rsdTypeToGLType(f->mHal.state.dataType);
+            mAttribs[userNum].normalized = f->mHal.state.dataType != RS_TYPE_FLOAT_32;
             mAttribs[userNum].stride = stride;
             String8 tmp(RS_SHADER_ATTR);
-            tmp.append(elem->getFieldName(fieldI));
+            tmp.append(elem->mHal.state.fieldNames[fieldI]);
             mAttribs[userNum].name.setTo(tmp.string());
 
             // Remember which allocation this attribute came from
@@ -133,7 +128,7 @@
 void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex,
                                       uint32_t start, uint32_t len) const {
     if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
-        ALOGE("Invalid mesh or parameters");
+        rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh or parameters");
         return;
     }
 
@@ -186,7 +181,7 @@
     rsdGLCheckError(rsc, "Mesh::renderPrimitiveRange");
 }
 
-void RsdMeshObj::updateGLPrimitives() {
+void RsdMeshObj::updateGLPrimitives(const Context *rsc) {
     mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount];
     for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) {
         switch (mRSMesh->mHal.state.primitives[i]) {
@@ -196,6 +191,7 @@
             case RS_PRIMITIVE_TRIANGLE:       mGLPrimitives[i] = GL_TRIANGLES; break;
             case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break;
             case RS_PRIMITIVE_TRIANGLE_FAN:   mGLPrimitives[i] = GL_TRIANGLE_FAN; break;
+            default: rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh primitive"); break;
         }
     }
 }
diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h
index 8b1271b..1370f01 100644
--- a/libs/rs/driver/rsdMeshObj.h
+++ b/libs/rs/driver/rsdMeshObj.h
@@ -37,15 +37,16 @@
             const android::renderscript::Mesh *);
     ~RsdMeshObj();
 
-    void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+    void renderPrimitiveRange(const android::renderscript::Context *,
+                              uint32_t primIndex, uint32_t start, uint32_t len) const;
 
-    bool init();
+    bool init(const android::renderscript::Context *rsc);
 
 protected:
     const android::renderscript::Mesh *mRSMesh;
 
     uint32_t *mGLPrimitives;
-    void updateGLPrimitives();
+    void updateGLPrimitives(const android::renderscript::Context *rsc);
 
     bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx);
     // Attribues that allow us to map to GL
diff --git a/libs/rs/driver/rsdPath.cpp b/libs/rs/driver/rsdPath.cpp
new file mode 100644
index 0000000..e04bc02
--- /dev/null
+++ b/libs/rs/driver/rsdPath.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsPath.h>
+
+#include "rsdCore.h"
+#include "rsdPath.h"
+#include "rsdAllocation.h"
+#include "rsdGL.h"
+#include "rsdVertexArray.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+class DrvPath {
+protected:
+    DrvPath();
+public:
+    virtual ~DrvPath();
+    virtual void draw(Context *) = 0;
+};
+
+class DrvPathStatic : public DrvPath {
+public:
+    typedef struct {
+        float x1, xc, x2;
+        float y1, yc, y2;
+    } segment_t;
+
+    segment_t *mSegments;
+    uint32_t mSegmentCount;
+
+    DrvPathStatic(const Allocation *vtx, const Allocation *loops);
+    virtual ~DrvPathStatic();
+
+    virtual void draw(Context *);
+};
+
+class DrvPathDynamic : public DrvPath {
+public:
+    DrvPathDynamic();
+    virtual ~DrvPathDynamic();
+};
+
+static void cleanup(const Context *rsc, const Path *m) {
+    DrvPath *dp = (DrvPath *)m->mHal.drv;
+    if (dp) {
+        delete dp;
+    }
+}
+
+bool rsdPathInitStatic(const Context *rsc, const Path *m,
+                       const Allocation *vtx, const Allocation *loops) {
+    DrvPathStatic *drv = NULL;
+    cleanup(rsc, m);
+
+    DrvPathStatic *dps = new DrvPathStatic(vtx, loops);
+    //LOGE("init path m %p,  %p", m, dps);
+    m->mHal.drv = dps;
+    return dps != NULL;
+}
+
+bool rsdPathInitDynamic(const Context *rsc, const Path *m) {
+    return false;
+}
+
+
+void rsdPathDraw(const Context *rsc, const Path *m) {
+    //LOGE("render m=%p", m);
+
+    DrvPath *drv = (DrvPath *)m->mHal.drv;
+    if(drv) {
+        //LOGE("render 2 drv=%p", drv);
+        drv->draw((Context *)rsc);
+    }
+}
+
+void rsdPathDestroy(const Context *rsc, const Path *m) {
+    cleanup(rsc, m);
+    m->mHal.drv = NULL;
+}
+
+
+
+
+DrvPath::DrvPath() {
+}
+
+DrvPath::~DrvPath() {
+}
+
+DrvPathStatic::DrvPathStatic(const Allocation *vtx, const Allocation *loops) {
+    mSegmentCount = vtx->getType()->getDimX() / 3;
+    mSegments = new segment_t[mSegmentCount];
+
+    const float *fin = (const float *)vtx->getPtr();
+    for (uint32_t ct=0; ct < mSegmentCount; ct++) {
+        segment_t *s = &mSegments[ct];
+        s->x1 = fin[0];
+        s->y1 = fin[1];
+
+        s->xc = fin[2];
+        s->yc = fin[3];
+
+        s->x2 = fin[4];
+        s->y2 = fin[5];
+        fin += 6;
+    }
+}
+
+DrvPathStatic::~DrvPathStatic() {
+}
+
+void DrvPathStatic::draw(Context *rsc) {
+    const static float color[24] = {
+        1.f, 0.f, 0.f, 1.f,  0.5f, 0.f, 0.f, 1.f,
+        1.f, 0.f, 0.f, 1.f,  0.5f, 0.f, 0.f, 1.f,
+        1.f, 1.f, 1.f, 1.f,  1.f, 1.f, 1.f, 1.f};
+    float vtx[12];
+
+    //LOGE("draw");
+    if (!rsc->setupCheck()) {
+        return;
+    }
+
+    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+    if (!dc->gl.shaderCache->setup(rsc)) {
+        return;
+    }
+
+    RsdVertexArray::Attrib attribs[2];
+    attribs[0].set(GL_FLOAT, 2, 8, false, (uint32_t)vtx, "ATTRIB_position");
+    attribs[1].set(GL_FLOAT, 4, 16, false, (uint32_t)color, "ATTRIB_color");
+    RsdVertexArray va(attribs, 2);
+    va.setup(rsc);
+
+    //LOGE("mSegmentCount %i", mSegmentCount);
+    for (uint32_t ct=0; ct < mSegmentCount; ct++) {
+        segment_t *s = &mSegments[ct];
+
+        vtx[0] = s->x1;
+        vtx[1] = s->y1;
+        vtx[2] = s->xc;
+        vtx[3] = s->yc;
+
+        vtx[4] = s->x2;
+        vtx[5] = s->y2;
+        vtx[6] = s->xc;
+        vtx[7] = s->yc;
+
+        vtx[8] = s->x1;
+        vtx[9] = s->y1;
+        vtx[10] = s->x2;
+        vtx[11] = s->y2;
+
+        RSD_CALL_GL(glDrawArrays, GL_LINES, 0, 6);
+    }
+
+}
+
+DrvPathDynamic::DrvPathDynamic() {
+}
+
+DrvPathDynamic::~DrvPathDynamic() {
+}
diff --git a/libs/rs/driver/rsdPath.h b/libs/rs/driver/rsdPath.h
new file mode 100644
index 0000000..fa00972
--- /dev/null
+++ b/libs/rs/driver/rsdPath.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSD_PATH_H
+#define RSD_PATH_H
+
+#include <rs_hal.h>
+
+
+bool rsdPathInitStatic(const android::renderscript::Context *rsc,
+                       const android::renderscript::Path *m,
+                       const android::renderscript::Allocation *vertex,
+                       const android::renderscript::Allocation *loops);
+bool rsdPathInitDynamic(const android::renderscript::Context *rsc,
+                        const android::renderscript::Path *m);
+void rsdPathDraw(const android::renderscript::Context *rsc,
+                 const android::renderscript::Path *m);
+void rsdPathDestroy(const android::renderscript::Context *rsc,
+                    const android::renderscript::Path *m);
+
+
+#endif
diff --git a/libs/rs/driver/rsdProgramRaster.cpp b/libs/rs/driver/rsdProgramRaster.cpp
index b493759..e5a0291 100644
--- a/libs/rs/driver/rsdProgramRaster.cpp
+++ b/libs/rs/driver/rsdProgramRaster.cpp
@@ -45,6 +45,9 @@
         case RS_CULL_NONE:
             RSD_CALL_GL(glDisable, GL_CULL_FACE);
             break;
+        default:
+            rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid cull type");
+            break;
     }
 
 }
diff --git a/libs/rs/driver/rsdProgramStore.cpp b/libs/rs/driver/rsdProgramStore.cpp
index fca9ba9..c1295e8 100644
--- a/libs/rs/driver/rsdProgramStore.cpp
+++ b/libs/rs/driver/rsdProgramStore.cpp
@@ -111,7 +111,7 @@
         drv->blendSrc = GL_SRC_ALPHA_SATURATE;
         break;
     default:
-        ALOGE("Unknown blend src mode.");
+        rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend src mode.");
         goto error;
     }
 
@@ -141,7 +141,7 @@
         drv->blendDst = GL_ONE_MINUS_DST_ALPHA;
         break;
     default:
-        ALOGE("Unknown blend dst mode.");
+        rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend dst mode.");
         goto error;
     }
 
diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp
index e315539..753ef73 100644
--- a/libs/rs/driver/rsdRuntimeMath.cpp
+++ b/libs/rs/driver/rsdRuntimeMath.cpp
@@ -329,6 +329,16 @@
     return prev;
 }
 
+static uint32_t SC_AtomicUMin(volatile uint32_t *ptr, uint32_t value) {
+    uint32_t prev, status;
+    do {
+        prev = *ptr;
+        uint32_t n = rsMin(value, prev);
+        status = android_atomic_release_cas((int32_t) prev, (int32_t)n, (volatile int32_t*) ptr);
+    } while (CC_UNLIKELY(status != 0));
+    return prev;
+}
+
 static int32_t SC_AtomicMin(volatile int32_t *ptr, int32_t value) {
     int32_t prev, status;
     do {
@@ -339,6 +349,16 @@
     return prev;
 }
 
+static uint32_t SC_AtomicUMax(volatile uint32_t *ptr, uint32_t value) {
+    uint32_t prev, status;
+    do {
+        prev = *ptr;
+        uint32_t n = rsMax(value, prev);
+        status = android_atomic_release_cas((int32_t) prev, (int32_t) n, (volatile int32_t*) ptr);
+    } while (CC_UNLIKELY(status != 0));
+    return prev;
+}
+
 static int32_t SC_AtomicMax(volatile int32_t *ptr, int32_t value) {
     int32_t prev, status;
     do {
@@ -524,9 +544,9 @@
     { "_Z11rsAtomicXorPVii", (void *)&SC_AtomicXor, true },
     { "_Z11rsAtomicXorPVjj", (void *)&SC_AtomicXor, true },
     { "_Z11rsAtomicMinPVii", (void *)&SC_AtomicMin, true },
-    { "_Z11rsAtomicMinPVjj", (void *)&SC_AtomicMin, true },
+    { "_Z11rsAtomicMinPVjj", (void *)&SC_AtomicUMin, true },
     { "_Z11rsAtomicMaxPVii", (void *)&SC_AtomicMax, true },
-    { "_Z11rsAtomicMaxPVjj", (void *)&SC_AtomicMax, true },
+    { "_Z11rsAtomicMaxPVjj", (void *)&SC_AtomicUMax, true },
     { "_Z11rsAtomicCasPViii", (void *)&SC_AtomicCas, true },
     { "_Z11rsAtomicCasPVjjj", (void *)&SC_AtomicCas, true },
 
diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index 14c2970..44bfb1c 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/driver/rsdRuntimeStubs.cpp
@@ -25,6 +25,7 @@
 #include "rsdCore.h"
 
 #include "rsdRuntime.h"
+#include "rsdPath.h"
 
 #include <time.h>
 
@@ -89,6 +90,16 @@
     rsrBindTexture(rsc, sc, pf, slot, a);
 }
 
+static void SC_BindVertexConstant(ProgramVertex *pv, uint32_t slot, Allocation *a) {
+    GET_TLS();
+    rsrBindConstant(rsc, sc, pv, slot, a);
+}
+
+static void SC_BindFragmentConstant(ProgramFragment *pf, uint32_t slot, Allocation *a) {
+    GET_TLS();
+    rsrBindConstant(rsc, sc, pf, slot, a);
+}
+
 static void SC_BindSampler(ProgramFragment *pf, uint32_t slot, Sampler *s) {
     GET_TLS();
     rsrBindSampler(rsc, sc, pf, slot, s);
@@ -204,6 +215,12 @@
     rsrDrawRect(rsc, sc, x1, y1, x2, y2, z);
 }
 
+static void SC_DrawPath(Path *p) {
+    GET_TLS();
+    //rsrDrawPath(rsc, sc, p);
+    rsdPathDraw(rsc, p);
+}
+
 static void SC_DrawMesh(Mesh *m) {
     GET_TLS();
     rsrDrawMesh(rsc, sc, m);
@@ -533,6 +550,10 @@
     { "_Z13rsClearObjectP9rs_script", (void *)&SC_ClearObject, true },
     { "_Z10rsIsObject9rs_script", (void *)&SC_IsObject, true },
 
+    { "_Z11rsSetObjectP7rs_pathS_", (void *)&SC_SetObject, true },
+    { "_Z13rsClearObjectP7rs_path", (void *)&SC_ClearObject, true },
+    { "_Z10rsIsObject7rs_path", (void *)&SC_IsObject, true },
+
     { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_SetObject, true },
     { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_ClearObject, true },
     { "_Z10rsIsObject7rs_mesh", (void *)&SC_IsObject, true },
@@ -580,6 +601,8 @@
     { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_BindProgramRaster, false },
     { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_BindSampler, false },
     { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_BindTexture, false },
+    { "_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation", (void *)&SC_BindFragmentConstant, false },
+    { "_Z15rsgBindConstant17rs_program_vertexj13rs_allocation", (void *)&SC_BindVertexConstant, false },
 
     { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadProjectionMatrix, false },
     { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadModelMatrix, false },
@@ -603,6 +626,8 @@
     { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_DrawMeshPrimitiveRange, false },
     { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_MeshComputeBoundingBox, false },
 
+    { "_Z11rsgDrawPath7rs_path", (void *)&SC_DrawPath, false },
+
     { "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false },
     { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false },
 
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index a10deb4..3bca794 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -90,12 +90,12 @@
     String8 s;
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
         const Element *e = mRSProgram->mHal.state.inputElements[ct];
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
+        for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+            const Element *f = e->mHal.state.fields[field];
 
             // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            switch (f->getComponent().getVectorSize()) {
+            rsAssert(!f->mHal.state.fieldsCount);
+            switch (f->mHal.state.vectorSize) {
             case 1: s.append("attribute float ATTRIB_"); break;
             case 2: s.append("attribute vec2 ATTRIB_"); break;
             case 3: s.append("attribute vec3 ATTRIB_"); break;
@@ -104,7 +104,7 @@
                 rsAssert(0);
             }
 
-            s.append(e->getFieldName(field));
+            s.append(e->mHal.state.fieldNames[field]);
             s.append(";\n");
         }
     }
@@ -114,17 +114,13 @@
 void RsdShader::appendAttributes() {
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
         const Element *e = mRSProgram->mHal.state.inputElements[ct];
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fn = e->getFieldName(field);
-
-            if (fn[0] == '#') {
-                continue;
-            }
+        for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+            const Element *f = e->mHal.state.fields[field];
+            const char *fn = e->mHal.state.fieldNames[field];
 
             // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            switch (f->getComponent().getVectorSize()) {
+            rsAssert(!f->mHal.state.fieldsCount);
+            switch (f->mHal.state.vectorSize) {
             case 1: mShader.append("attribute float ATTRIB_"); break;
             case 2: mShader.append("attribute vec2 ATTRIB_"); break;
             case 3: mShader.append("attribute vec3 ATTRIB_"); break;
@@ -143,7 +139,12 @@
     char buf[256];
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
         if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
-            snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+            Allocation *a = mRSProgram->mHal.state.textures[ct];
+            if (a && a->mHal.state.surfaceTextureID) {
+                snprintf(buf, sizeof(buf), "uniform samplerExternalOES UNI_Tex%i;\n", ct);
+            } else {
+                snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+            }
             mTextureTargets[ct] = GL_TEXTURE_2D;
         } else {
             snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
@@ -190,12 +191,11 @@
                 char* buf = (char*) malloc(infoLen);
                 if (buf) {
                     RSD_CALL_GL(glGetShaderInfoLog, mShaderID, infoLen, NULL, buf);
-                    ALOGE("Could not compile shader \n%s\n", buf);
+                    rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
                     free(buf);
                 }
                 RSD_CALL_GL(glDeleteShader, mShaderID);
                 mShaderID = 0;
-                rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
                 return false;
             }
         }
@@ -211,24 +211,20 @@
 void RsdShader::appendUserConstants() {
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
         const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fn = e->getFieldName(field);
-
-            if (fn[0] == '#') {
-                continue;
-            }
+        for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+            const Element *f = e->mHal.state.fields[field];
+            const char *fn = e->mHal.state.fieldNames[field];
 
             // Cannot be complex
-            rsAssert(!f->getFieldCount());
-            if (f->getType() == RS_TYPE_MATRIX_4X4) {
+            rsAssert(!f->mHal.state.fieldsCount);
+            if (f->mHal.state.dataType == RS_TYPE_MATRIX_4X4) {
                 mShader.append("uniform mat4 UNI_");
-            } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
+            } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_3X3) {
                 mShader.append("uniform mat3 UNI_");
-            } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
+            } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_2X2) {
                 mShader.append("uniform mat2 UNI_");
             } else {
-                switch (f->getComponent().getVectorSize()) {
+                switch (f->mHal.state.vectorSize) {
                 case 1: mShader.append("uniform float UNI_"); break;
                 case 2: mShader.append("uniform vec2 UNI_"); break;
                 case 3: mShader.append("uniform vec3 UNI_"); break;
@@ -239,8 +235,8 @@
             }
 
             mShader.append(fn);
-            if (e->getFieldArraySize(field) > 1) {
-                mShader.appendFormat("[%d]", e->getFieldArraySize(field));
+            if (e->mHal.state.fieldArraySizes[field] > 1) {
+                mShader.appendFormat("[%d]", e->mHal.state.fieldArraySizes[field]);
             }
             mShader.append(";\n");
         }
@@ -248,8 +244,8 @@
 }
 
 void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
-    RsDataType dataType = field->getType();
-    uint32_t elementSize = field->getSizeBytes() / sizeof(float);
+    RsDataType dataType = field->mHal.state.dataType;
+    uint32_t elementSize = field->mHal.state.elementSizeBytes / sizeof(float);
     for (uint32_t i = 0; i < arraySize; i ++) {
         if (arraySize > 1) {
             ALOGV("Array Element [%u]", i);
@@ -270,7 +266,7 @@
             ALOGV("{%f, %f",  fd[0], fd[2]);
             ALOGV(" %f, %f}", fd[1], fd[3]);
         } else {
-            switch (field->getComponent().getVectorSize()) {
+            switch (field->mHal.state.vectorSize) {
             case 1:
                 ALOGV("Uniform 1 = %f", fd[0]);
                 break;
@@ -295,7 +291,7 @@
 
 void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd,
                          int32_t slot, uint32_t arraySize ) {
-    RsDataType dataType = field->getType();
+    RsDataType dataType = field->mHal.state.dataType;
     if (dataType == RS_TYPE_MATRIX_4X4) {
         RSD_CALL_GL(glUniformMatrix4fv, slot, arraySize, GL_FALSE, fd);
     } else if (dataType == RS_TYPE_MATRIX_3X3) {
@@ -303,7 +299,7 @@
     } else if (dataType == RS_TYPE_MATRIX_2X2) {
         RSD_CALL_GL(glUniformMatrix2fv, slot, arraySize, GL_FALSE, fd);
     } else {
-        switch (field->getComponent().getVectorSize()) {
+        switch (field->mHal.state.vectorSize) {
         case 1:
             RSD_CALL_GL(glUniform1fv, slot, arraySize, fd);
             break;
@@ -349,8 +345,8 @@
 
     if (!dc->gl.gl.OES_texture_npot && tex->getType()->getIsNp2()) {
         if (tex->getHasGraphicsMipmaps() &&
-            (dc->gl.gl.GL_NV_texture_npot_2D_mipmap || dc->gl.gl.GL_IMG_texture_npot)) {
-            if (dc->gl.gl.GL_NV_texture_npot_2D_mipmap) {
+            (dc->gl.gl.NV_texture_npot_2D_mipmap || dc->gl.gl.IMG_texture_npot)) {
+            if (dc->gl.gl.NV_texture_npot_2D_mipmap) {
                 RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
                             trans[s->mHal.state.minFilter]);
             } else {
@@ -458,15 +454,11 @@
 
         const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
         const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
-        for (uint32_t field=0; field < e->getFieldCount(); field++) {
-            const Element *f = e->getField(field);
-            const char *fieldName = e->getFieldName(field);
-            // If this field is padding, skip it
-            if (fieldName[0] == '#') {
-                continue;
-            }
+        for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+            const Element *f = e->mHal.state.fields[field];
+            const char *fieldName = e->mHal.state.fieldNames[field];
 
-            uint32_t offset = e->getFieldOffsetBytes(field);
+            uint32_t offset = e->mHal.state.fieldOffsetBytes[field];
             const float *fd = reinterpret_cast<const float *>(&data[offset]);
 
             int32_t slot = -1;
@@ -505,22 +497,13 @@
     mAttribCount = 0;
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
         const Element *elem = mRSProgram->mHal.state.inputElements[ct];
-        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
-            if (elem->getFieldName(field)[0] != '#') {
-                mAttribCount ++;
-            }
-        }
+        mAttribCount += elem->mHal.state.fieldsCount;
     }
 
     mUniformCount = 0;
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
         const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement();
-
-        for (uint32_t field=0; field < elem->getFieldCount(); field++) {
-            if (elem->getFieldName(field)[0] != '#') {
-                mUniformCount ++;
-            }
-        }
+        mUniformCount += elem->mHal.state.fieldsCount;
     }
     mUniformCount += mRSProgram->mHal.state.texturesCount;
 
@@ -540,17 +523,17 @@
 
 void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths,
                                    uint32_t *count, const char *prefix) {
-    rsAssert(e->getFieldCount());
-    for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
-        const Element *ce = e->getField(ct);
-        if (ce->getFieldCount()) {
+    rsAssert(e->mHal.state.fieldsCount);
+    for (uint32_t ct=0; ct < e->mHal.state.fieldsCount; ct++) {
+        const Element *ce = e->mHal.state.fields[ct];
+        if (ce->mHal.state.fieldsCount) {
             initAddUserElement(ce, names, arrayLengths, count, prefix);
-        } else if (e->getFieldName(ct)[0] != '#') {
+        } else {
             String8 tmp(prefix);
-            tmp.append(e->getFieldName(ct));
+            tmp.append(e->mHal.state.fieldNames[ct]);
             names[*count].setTo(tmp.string());
             if (arrayLengths) {
-                arrayLengths[*count] = e->getFieldArraySize(ct);
+                arrayLengths[*count] = e->mHal.state.fieldArraySizes[ct];
             }
             (*count)++;
         }
diff --git a/libs/rs/driver/rsdShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
index f6236e7..89d3c45 100644
--- a/libs/rs/driver/rsdShaderCache.cpp
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -167,12 +167,11 @@
                 char* buf = (char*) malloc(bufLength);
                 if (buf) {
                     glGetProgramInfoLog(pgm, bufLength, NULL, buf);
-                    ALOGE("Could not link program:\n%s\n", buf);
+                    rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
                     free(buf);
                 }
             }
             glDeleteProgram(pgm);
-            rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, "Error linking GL Programs");
             return false;
         }
 
diff --git a/libs/rs/driver/rsdShaderCache.h b/libs/rs/driver/rsdShaderCache.h
index 17ee3e8..0beecae 100644
--- a/libs/rs/driver/rsdShaderCache.h
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -98,7 +98,8 @@
     struct ProgramEntry {
         ProgramEntry(uint32_t numVtxAttr, uint32_t numVtxUnis,
                      uint32_t numFragUnis) : vtx(0), frag(0), program(0), vtxAttrCount(0),
-                                             vtxAttrs(0), vtxUniforms(0), fragUniforms(0) {
+                                             vtxAttrs(0), vtxUniforms(0), fragUniforms(0),
+                                             fragUniformIsSTO(0) {
             vtxAttrCount = numVtxAttr;
             if (numVtxAttr) {
                 vtxAttrs = new AttrData[numVtxAttr];
@@ -108,6 +109,7 @@
             }
             if (numFragUnis) {
                 fragUniforms = new UniformData[numFragUnis];
+                fragUniformIsSTO = new bool[numFragUnis];
             }
         }
         ~ProgramEntry() {
@@ -123,6 +125,10 @@
                 delete[] fragUniforms;
                 fragUniforms = NULL;
             }
+            if (fragUniformIsSTO) {
+                delete[] fragUniformIsSTO;
+                fragUniformIsSTO = NULL;
+            }
         }
         uint32_t vtx;
         uint32_t frag;
@@ -131,6 +137,7 @@
         AttrData *vtxAttrs;
         UniformData *vtxUniforms;
         UniformData *fragUniforms;
+        bool *fragUniformIsSTO;
     };
     android::Vector<ProgramEntry*> mEntries;
     ProgramEntry *mCurrent;
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 20b1f52..6759bc7 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -42,6 +42,7 @@
     param RsType vtype
     param RsAllocationMipmapControl mips
     param uint32_t usages
+    param uint32_t ptr
     ret RsAllocation
 }
 
@@ -63,7 +64,10 @@
     ret RsAllocation
 }
 
-
+AllocationGetSurfaceTextureID {
+    param RsAllocation alloc
+    ret int32_t
+}
 
 ContextFinish {
 	sync
@@ -115,6 +119,7 @@
 	}
 
 ContextDestroyWorker {
+        sync
 }
 
 AssignName {
@@ -162,7 +167,7 @@
 	param uint32_t x
 	param uint32_t lod
 	param const void *data
-	param uint32_t comp_offset
+	param size_t comp_offset
 	}
 
 Allocation2DData {
@@ -183,7 +188,7 @@
 	param uint32_t lod
 	param RsAllocationCubemapFace face
 	param const void *data
-	param uint32_t element_offset
+	param size_t element_offset
 	}
 
 AllocationGenerateMipmaps {
@@ -388,3 +393,13 @@
 	param uint32_t *primType
 	ret RsMesh
 	}
+
+PathCreate {
+    param RsPathPrimitive pp
+    param bool isStatic
+    param RsAllocation vertex
+    param RsAllocation loops
+    param float quality
+    ret RsPath
+    }
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 2773d5c..02c6809 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-2012 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.
@@ -22,21 +22,22 @@
 using namespace android::renderscript;
 
 Allocation::Allocation(Context *rsc, const Type *type, uint32_t usages,
-                       RsAllocationMipmapControl mc)
+                       RsAllocationMipmapControl mc, void * ptr)
     : ObjectBase(rsc) {
 
     memset(&mHal, 0, sizeof(mHal));
     mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE;
     mHal.state.usageFlags = usages;
     mHal.state.mipmapControl = mc;
+    mHal.state.usrPtr = ptr;
 
     setType(type);
     updateCache();
 }
 
 Allocation * Allocation::createAllocation(Context *rsc, const Type *type, uint32_t usages,
-                              RsAllocationMipmapControl mc) {
-    Allocation *a = new Allocation(rsc, type, usages, mc);
+                              RsAllocationMipmapControl mc, void * ptr) {
+    Allocation *a = new Allocation(rsc, type, usages, mc, ptr);
 
     if (!rsc->mHal.funcs.allocation.init(rsc, a, type->getElement()->getHasReferences())) {
         rsc->setError(RS_ERROR_FATAL_DRIVER, "Allocation::Allocation, alloc failure");
@@ -71,11 +72,11 @@
 }
 
 void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod,
-                         uint32_t count, const void *data, uint32_t sizeBytes) {
-    const uint32_t eSize = mHal.state.type->getElementSizeBytes();
+                         uint32_t count, const void *data, size_t sizeBytes) {
+    const size_t eSize = mHal.state.type->getElementSizeBytes();
 
     if ((count * eSize) != sizeBytes) {
-        ALOGE("Allocation::subData called with mismatched size expected %i, got %i",
+        ALOGE("Allocation::subData called with mismatched size expected %zu, got %zu",
              (count * eSize), sizeBytes);
         mHal.state.type->dumpLOGV("type info");
         return;
@@ -86,14 +87,14 @@
 }
 
 void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
-             uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
-    const uint32_t eSize = mHal.state.elementSizeBytes;
-    const uint32_t lineSize = eSize * w;
+             uint32_t w, uint32_t h, const void *data, size_t sizeBytes) {
+    const size_t eSize = mHal.state.elementSizeBytes;
+    const size_t lineSize = eSize * w;
 
     //ALOGE("data2d %p,  %i %i %i %i %i %i %p %i", this, xoff, yoff, lod, face, w, h, data, sizeBytes);
 
     if ((lineSize * h) != sizeBytes) {
-        ALOGE("Allocation size mismatch, expected %i, got %i", (lineSize * h), sizeBytes);
+        ALOGE("Allocation size mismatch, expected %zu, got %zu", (lineSize * h), sizeBytes);
         rsAssert(!"Allocation::subData called with mismatched size");
         return;
     }
@@ -104,12 +105,12 @@
 
 void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff,
                       uint32_t lod, RsAllocationCubemapFace face,
-                      uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
+                      uint32_t w, uint32_t h, uint32_t d, const void *data, size_t sizeBytes) {
 }
 
 void Allocation::elementData(Context *rsc, uint32_t x, const void *data,
-                                uint32_t cIdx, uint32_t sizeBytes) {
-    uint32_t eSize = mHal.state.elementSizeBytes;
+                                uint32_t cIdx, size_t sizeBytes) {
+    size_t eSize = mHal.state.elementSizeBytes;
 
     if (cIdx >= mHal.state.type->getElement()->getFieldCount()) {
         ALOGE("Error Allocation::subElementData component %i out of range.", cIdx);
@@ -124,8 +125,9 @@
     }
 
     const Element * e = mHal.state.type->getElement()->getField(cIdx);
-    if (sizeBytes != e->getSizeBytes()) {
-        ALOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
+    uint32_t elemArraySize = mHal.state.type->getElement()->getFieldArraySize(cIdx);
+    if (sizeBytes != e->getSizeBytes() * elemArraySize) {
+        ALOGE("Error Allocation::subElementData data size %zu does not match field size %zu.", sizeBytes, e->getSizeBytes());
         rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
         return;
     }
@@ -135,8 +137,8 @@
 }
 
 void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y,
-                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
-    uint32_t eSize = mHal.state.elementSizeBytes;
+                                const void *data, uint32_t cIdx, size_t sizeBytes) {
+    size_t eSize = mHal.state.elementSizeBytes;
 
     if (x >= mHal.state.dimensionX) {
         ALOGE("Error Allocation::subElementData X offset %i out of range.", x);
@@ -157,9 +159,9 @@
     }
 
     const Element * e = mHal.state.type->getElement()->getField(cIdx);
-
-    if (sizeBytes != e->getSizeBytes()) {
-        ALOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
+    uint32_t elemArraySize = mHal.state.type->getElement()->getFieldArraySize(cIdx);
+    if (sizeBytes != e->getSizeBytes() * elemArraySize) {
+        ALOGE("Error Allocation::subElementData data size %zu does not match field size %zu.", sizeBytes, e->getSizeBytes());
         rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
         return;
     }
@@ -249,7 +251,7 @@
     delete[] sizeUnpadded;
 }
 
-void Allocation::unpackVec3Allocation(const void *data, uint32_t dataSize) {
+void Allocation::unpackVec3Allocation(const void *data, size_t dataSize) {
     const uint8_t *src = (const uint8_t*)data;
     uint8_t *dst = (uint8_t*)getPtr();
 
@@ -412,6 +414,12 @@
     ALOGE("not implemented");
 }
 
+int32_t Allocation::getSurfaceTextureID(const Context *rsc) {
+    int32_t id = rsc->mHal.funcs.allocation.initSurfaceTexture(rsc, this);
+    mHal.state.surfaceTextureID = id;
+    return id;
+}
+
 /////////////////
 //
 
@@ -519,13 +527,13 @@
 }
 
 void rsi_Allocation2DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, uint32_t lod, RsAllocationCubemapFace face,
-                                 const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped
+                                 const void *data, size_t sizeBytes, size_t eoff) {
     Allocation *a = static_cast<Allocation *>(va);
     a->elementData(rsc, x, y, data, eoff, sizeBytes);
 }
 
 void rsi_Allocation1DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t lod,
-                                 const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped
+                                 const void *data, size_t sizeBytes, size_t eoff) {
     Allocation *a = static_cast<Allocation *>(va);
     a->elementData(rsc, x, data, eoff, sizeBytes);
 }
@@ -570,8 +578,8 @@
 
 RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype,
                                        RsAllocationMipmapControl mips,
-                                       uint32_t usages) {
-    Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips);
+                                       uint32_t usages, uint32_t ptr) {
+    Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips, (void *)ptr);
     if (!alloc) {
         return NULL;
     }
@@ -584,7 +592,7 @@
                                             const void *data, size_t data_length, uint32_t usages) {
     Type *t = static_cast<Type *>(vtype);
 
-    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
+    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0);
     Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
     if (texAlloc == NULL) {
         ALOGE("Memory allocation failure");
@@ -608,7 +616,7 @@
     // Cubemap allocation's faces should be Width by Width each.
     // Source data should have 6 * Width by Width pixels
     // Error checking is done in the java layer
-    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
+    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0);
     Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
     if (texAlloc == NULL) {
         ALOGE("Memory allocation failure");
@@ -657,6 +665,11 @@
                                            (RsAllocationCubemapFace)srcFace);
 }
 
+int32_t rsi_AllocationGetSurfaceTextureID(Context *rsc, RsAllocation valloc) {
+    Allocation *alloc = static_cast<Allocation *>(valloc);
+    return alloc->getSurfaceTextureID(rsc);
+}
+
 }
 }
 
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 4ce863a..58a582b 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-2012 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.
@@ -55,6 +55,8 @@
             bool hasMipmaps;
             bool hasFaces;
             bool hasReferences;
+            void * usrPtr;
+            int32_t surfaceTextureID;
         };
         State state;
 
@@ -66,7 +68,8 @@
     Hal mHal;
 
     static Allocation * createAllocation(Context *rsc, const Type *, uint32_t usages,
-                                  RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE);
+                                         RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE,
+                                         void *ptr = 0);
     virtual ~Allocation();
     void updateCache();
 
@@ -80,16 +83,16 @@
     void resize1D(Context *rsc, uint32_t dimX);
     void resize2D(Context *rsc, uint32_t dimX, uint32_t dimY);
 
-    void data(Context *rsc, uint32_t xoff, uint32_t lod, uint32_t count, const void *data, uint32_t sizeBytes);
+    void data(Context *rsc, uint32_t xoff, uint32_t lod, uint32_t count, const void *data, size_t sizeBytes);
     void data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
-                 uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes);
+                 uint32_t w, uint32_t h, const void *data, size_t sizeBytes);
     void data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t lod, RsAllocationCubemapFace face,
-                 uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes);
+                 uint32_t w, uint32_t h, uint32_t d, const void *data, size_t sizeBytes);
 
     void elementData(Context *rsc, uint32_t x,
-                        const void *data, uint32_t elementOff, uint32_t sizeBytes);
+                     const void *data, uint32_t elementOff, size_t sizeBytes);
     void elementData(Context *rsc, uint32_t x, uint32_t y,
-                        const void *data, uint32_t elementOff, uint32_t sizeBytes);
+                     const void *data, uint32_t elementOff, size_t sizeBytes);
 
     void read(void *data);
 
@@ -123,6 +126,7 @@
         return mHal.state.mipmapControl != RS_ALLOCATION_MIPMAP_NONE;
     }
 
+    int32_t getSurfaceTextureID(const Context *rsc);
 
 protected:
     Vector<const Program *> mToDirtyList;
@@ -134,11 +138,11 @@
 
 private:
     void freeChildrenUnlocked();
-    Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc);
+    Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc, void *ptr);
 
     uint32_t getPackedSize() const;
     static void writePackedData(const Type *type, uint8_t *dst, const uint8_t *src, bool dstPadded);
-    void unpackVec3Allocation(const void *data, uint32_t dataSize);
+    void unpackVec3Allocation(const void *data, size_t dataSize);
     void packVec3Allocation(OStream *stream) const;
 };
 
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
index 21b98f6..9c2c200 100644
--- a/libs/rs/rsComponent.cpp
+++ b/libs/rs/rsComponent.cpp
@@ -62,6 +62,7 @@
         rsAssert(mNormalized == true);
         break;
     default:
+        rsAssert(mKind != RS_KIND_INVALID);
         break;
     }
 
@@ -167,6 +168,9 @@
     case RS_TYPE_BOOLEAN:
         mTypeBits = 8;
         break;
+    default:
+        rsAssert(mType != RS_TYPE_INVALID);
+        break;
     }
 
     mBitsUnpadded = mTypeBits * mVectorSize;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index ad2ff0f..adaefc6 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -18,6 +18,7 @@
 #include "rsContext.h"
 #include "rsThreadIO.h"
 #include <ui/FramebufferNativeWindow.h>
+#include <gui/DisplayEventReceiver.h>
 
 #include <sys/types.h>
 #include <sys/resource.h>
@@ -245,42 +246,55 @@
     }
 
     rsc->mRunning = true;
-    bool mDraw = true;
-    bool doWait = true;
-
-    uint64_t targetTime = rsc->getTime();
-    while (!rsc->mExit) {
-        uint64_t waitTime = 0;
-        uint64_t now = rsc->getTime();
-        if (!doWait) {
-            if (now < targetTime) {
-                waitTime = targetTime - now;
-                doWait = true;
-            }
+    if (!rsc->mIsGraphicsContext) {
+        while (!rsc->mExit) {
+            rsc->mIO.playCoreCommands(rsc, -1);
         }
+    } else {
+#ifndef ANDROID_RS_SERIALIZE
+        DisplayEventReceiver displayEvent;
+        DisplayEventReceiver::Event eventBuffer[1];
+#endif
+        int vsyncRate = 0;
+        int targetRate = 0;
 
-        mDraw |= rsc->mIO.playCoreCommands(rsc, doWait, waitTime);
-        mDraw &= (rsc->mRootScript.get() != NULL);
-        mDraw &= rsc->mHasSurface;
+        bool drawOnce = false;
+        while (!rsc->mExit) {
+            rsc->timerSet(RS_TIMER_IDLE);
 
-        if (mDraw && rsc->mIsGraphicsContext) {
-            uint64_t delay = rsc->runRootScript() * 1000000;
-            targetTime = rsc->getTime() + delay;
-            doWait = (delay == 0);
-
-            if (rsc->props.mLogVisual) {
-                rsc->displayDebugStats();
+#ifndef ANDROID_RS_SERIALIZE
+            if (vsyncRate != targetRate) {
+                displayEvent.setVsyncRate(targetRate);
+                vsyncRate = targetRate;
+            }
+            if (targetRate) {
+                drawOnce |= rsc->mIO.playCoreCommands(rsc, displayEvent.getFd());
+                while (displayEvent.getEvents(eventBuffer, 1) != 0) {
+                    //ALOGE("vs2 time past %lld", (rsc->getTime() - eventBuffer[0].header.timestamp) / 1000000);
+                }
+            } else
+#endif
+            {
+                drawOnce |= rsc->mIO.playCoreCommands(rsc, -1);
             }
 
-            mDraw = !rsc->mPaused;
-            rsc->timerSet(RS_TIMER_CLEAR_SWAP);
-            rsc->mHal.funcs.swap(rsc);
-            rsc->timerFrame();
-            rsc->timerSet(RS_TIMER_INTERNAL);
-            rsc->timerPrint();
-            rsc->timerReset();
-        } else {
-            doWait = true;
+            if ((rsc->mRootScript.get() != NULL) && rsc->mHasSurface &&
+                (targetRate || drawOnce) && !rsc->mPaused) {
+
+                drawOnce = false;
+                targetRate = ((rsc->runRootScript() + 15) / 16);
+
+                if (rsc->props.mLogVisual) {
+                    rsc->displayDebugStats();
+                }
+
+                rsc->timerSet(RS_TIMER_CLEAR_SWAP);
+                rsc->mHal.funcs.swap(rsc);
+                rsc->timerFrame();
+                rsc->timerSet(RS_TIMER_INTERNAL);
+                rsc->timerPrint();
+                rsc->timerReset();
+            }
         }
     }
 
@@ -315,8 +329,8 @@
          mFBOCache.deinit(this);
     }
     ObjectBase::freeAllChildren(this);
-    //ALOGV("destroyWorkerThreadResources 2");
     mExit = true;
+    //ALOGV("destroyWorkerThreadResources 2");
 }
 
 void Context::printWatchdogInfo(void *ctx) {
@@ -347,6 +361,7 @@
 #else
     setpriority(PRIO_PROCESS, mNativeThreadId, p);
 #endif
+    mHal.funcs.setPriority(this, mThreadPriority);
 }
 
 Context::Context() {
@@ -382,7 +397,7 @@
     pthread_mutex_lock(&gInitMutex);
 
     mIO.init();
-    mIO.setTimoutCallback(printWatchdogInfo, this, 2e9);
+    mIO.setTimeoutCallback(printWatchdogInfo, this, 2e9);
 
     dev->addContext(this);
     mDev = dev;
@@ -434,14 +449,12 @@
     ALOGV("%p Context::~Context", this);
 
     if (!mIsContextLite) {
-        mIO.coreFlush();
-        rsAssert(mExit);
-        mExit = true;
         mPaused = false;
         void *res;
 
         mIO.shutdown();
         int status = pthread_join(mThreadId, &res);
+        rsAssert(mExit);
 
         if (mHal.funcs.shutdownDriver) {
             mHal.funcs.shutdownDriver(this);
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 61c29f9..05c799e 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -32,6 +32,7 @@
 #include "rsAdapter.h"
 #include "rsSampler.h"
 #include "rsFont.h"
+#include "rsPath.h"
 #include "rsProgramFragment.h"
 #include "rsProgramStore.h"
 #include "rsProgramRaster.h"
@@ -39,7 +40,6 @@
 #include "rsFBOCache.h"
 
 #include "rsgApiStructs.h"
-#include "rsLocklessFifo.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index dff9585..fb2892c 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -27,6 +27,7 @@
     mFields = NULL;
     mFieldCount = 0;
     mHasReference = false;
+    memset(&mHal, 0, sizeof(mHal));
 }
 
 Element::~Element() {
@@ -47,6 +48,12 @@
     mFields = NULL;
     mFieldCount = 0;
     mHasReference = false;
+
+    delete [] mHal.state.fields;
+    delete [] mHal.state.fieldArraySizes;
+    delete [] mHal.state.fieldNames;
+    delete [] mHal.state.fieldNameLengths;
+    delete [] mHal.state.fieldOffsetBytes;
 }
 
 size_t Element::getSizeBits() const {
@@ -157,16 +164,36 @@
 }
 
 void Element::compute() {
+    mHal.state.dataType = mComponent.getType();
+    mHal.state.dataKind = mComponent.getKind();
+    mHal.state.vectorSize = mComponent.getVectorSize();
+
     if (mFieldCount == 0) {
         mBits = mComponent.getBits();
         mBitsUnpadded = mComponent.getBitsUnpadded();
         mHasReference = mComponent.isReference();
+
+        mHal.state.elementSizeBytes = getSizeBytes();
         return;
     }
 
+    uint32_t noPaddingFieldCount = 0;
+    for (uint32_t ct = 0; ct < mFieldCount; ct ++) {
+        if (mFields[ct].name.string()[0] != '#') {
+            noPaddingFieldCount ++;
+        }
+    }
+
+    mHal.state.fields = new const Element*[noPaddingFieldCount];
+    mHal.state.fieldArraySizes = new uint32_t[noPaddingFieldCount];
+    mHal.state.fieldNames = new const char*[noPaddingFieldCount];
+    mHal.state.fieldNameLengths = new uint32_t[noPaddingFieldCount];
+    mHal.state.fieldOffsetBytes = new uint32_t[noPaddingFieldCount];
+    mHal.state.fieldsCount = noPaddingFieldCount;
+
     size_t bits = 0;
     size_t bitsUnpadded = 0;
-    for (size_t ct=0; ct < mFieldCount; ct++) {
+    for (size_t ct = 0, ctNoPadding = 0; ct < mFieldCount; ct++) {
         mFields[ct].offsetBits = bits;
         mFields[ct].offsetBitsUnpadded = bitsUnpadded;
         bits += mFields[ct].e->getSizeBits() * mFields[ct].arraySize;
@@ -175,8 +202,21 @@
         if (mFields[ct].e->mHasReference) {
             mHasReference = true;
         }
+
+        if (mFields[ct].name.string()[0] == '#') {
+            continue;
+        }
+
+        mHal.state.fields[ctNoPadding] = mFields[ct].e.get();
+        mHal.state.fieldArraySizes[ctNoPadding] = mFields[ct].arraySize;
+        mHal.state.fieldNames[ctNoPadding] = mFields[ct].name.string();
+        mHal.state.fieldNameLengths[ctNoPadding] = mFields[ct].name.length() + 1; // to include 0
+        mHal.state.fieldOffsetBytes[ctNoPadding] = mFields[ct].offsetBits >> 3;
+
+        ctNoPadding ++;
     }
 
+    mHal.state.elementSizeBytes = getSizeBytes();
 }
 
 ObjectBaseRef<const Element> Element::createRef(Context *rsc, RsDataType dt, RsDataKind dk,
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index 04010fa..4b6b460 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -24,10 +24,38 @@
 // ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
 // An element is a group of Components that occupies one cell in a structure.
 class Element : public ObjectBase {
 public:
+    struct Hal {
+        mutable void *drv;
+
+        struct State {
+            RsDataType dataType;
+            RsDataKind dataKind;
+            uint32_t vectorSize;
+            uint32_t elementSizeBytes;
+
+            // Subelements
+            const Element **fields;
+            uint32_t *fieldArraySizes;
+            const char **fieldNames;
+            uint32_t *fieldNameLengths;
+            uint32_t *fieldOffsetBytes;
+            uint32_t fieldsCount;
+        };
+        State state;
+    };
+    Hal mHal;
+
     class Builder {
     public:
         Builder();
diff --git a/libs/rs/rsFifo.h b/libs/rs/rsFifo.h
index f924b95..911f446 100644
--- a/libs/rs/rsFifo.h
+++ b/libs/rs/rsFifo.h
@@ -35,9 +35,9 @@
     virtual ~Fifo();
 
 public:
-    void virtual writeAsync(const void *data, size_t bytes) = 0;
+    bool virtual writeAsync(const void *data, size_t bytes, bool waitForSpace = true) = 0;
     void virtual writeWaitReturn(void *ret, size_t retSize) = 0;
-    size_t virtual read(void *data, size_t bytes) = 0;
+    size_t virtual read(void *data, size_t bytes, bool doWait = true, uint64_t timeToWait = 0) = 0;
     void virtual readReturn(const void *data, size_t bytes) = 0;
 
     void virtual flush() = 0;
diff --git a/libs/rs/rsFifoSocket.cpp b/libs/rs/rsFifoSocket.cpp
index 163a44b..bd511cf 100644
--- a/libs/rs/rsFifoSocket.cpp
+++ b/libs/rs/rsFifoSocket.cpp
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <unistd.h>
+#include <poll.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 
@@ -29,55 +30,79 @@
 using namespace android::renderscript;
 
 FifoSocket::FifoSocket() {
-    sequence = 1;
+    mShutdown = false;
 }
 
 FifoSocket::~FifoSocket() {
 
 }
 
-bool FifoSocket::init() {
+bool FifoSocket::init(bool supportNonBlocking, bool supportReturnValues, size_t maxDataSize) {
     int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
     return false;
 }
 
 void FifoSocket::shutdown() {
+    mShutdown = true;
+    uint64_t d = 0;
+    ::send(sv[0], &d, sizeof(d), 0);
+    ::send(sv[1], &d, sizeof(d), 0);
+    close(sv[0]);
+    close(sv[1]);
 }
 
-void FifoSocket::writeAsync(const void *data, size_t bytes) {
+bool FifoSocket::writeAsync(const void *data, size_t bytes, bool waitForSpace) {
     if (bytes == 0) {
-        return;
+        return true;
     }
     //ALOGE("writeAsync %p %i", data, bytes);
     size_t ret = ::send(sv[0], data, bytes, 0);
     //ALOGE("writeAsync ret %i", ret);
     rsAssert(ret == bytes);
+    return true;
 }
 
 void FifoSocket::writeWaitReturn(void *retData, size_t retBytes) {
+    if (mShutdown) {
+        return;
+    }
+
     //ALOGE("writeWaitReturn %p %i", retData, retBytes);
-    size_t ret = ::recv(sv[0], retData, retBytes, 0);
+    size_t ret = ::recv(sv[0], retData, retBytes, MSG_WAITALL);
     //ALOGE("writeWaitReturn %i", ret);
     rsAssert(ret == retBytes);
 }
 
 size_t FifoSocket::read(void *data, size_t bytes) {
+    if (mShutdown) {
+        return 0;
+    }
+
     //ALOGE("read %p %i", data, bytes);
-    size_t ret = ::recv(sv[1], data, bytes, 0);
-    rsAssert(ret == bytes);
-    //ALOGE("read ret %i", ret);
+    size_t ret = ::recv(sv[1], data, bytes, MSG_WAITALL);
+    rsAssert(ret == bytes || mShutdown);
+    //ALOGE("read ret %i  bytes %i", ret, bytes);
+    if (mShutdown) {
+        ret = 0;
+    }
     return ret;
 }
 
-void FifoSocket::readReturn(const void *data, size_t bytes) {
-    ALOGE("readReturn %p %Zu", data, bytes);
-    size_t ret = ::send(sv[1], data, bytes, 0);
-    ALOGE("readReturn %Zu", ret);
-    rsAssert(ret == bytes);
+bool FifoSocket::isEmpty() {
+    struct pollfd p;
+    p.fd = sv[1];
+    p.events = POLLIN;
+    int r = poll(&p, 1, 0);
+    //ALOGE("poll r=%i", r);
+    return r == 0;
 }
 
 
-void FifoSocket::flush() {
+void FifoSocket::readReturn(const void *data, size_t bytes) {
+    //ALOGE("readReturn %p %Zu", data, bytes);
+    size_t ret = ::send(sv[1], data, bytes, 0);
+    //ALOGE("readReturn %Zu", ret);
+    //rsAssert(ret == bytes);
 }
 
 
diff --git a/libs/rs/rsFifoSocket.h b/libs/rs/rsFifoSocket.h
index 7df2b67..cac0a75 100644
--- a/libs/rs/rsFifoSocket.h
+++ b/libs/rs/rsFifoSocket.h
@@ -29,23 +29,23 @@
     FifoSocket();
     virtual ~FifoSocket();
 
-    bool init();
+    bool init(bool supportNonBlocking = true,
+              bool supportReturnValues = true,
+              size_t maxDataSize = 0);
     void shutdown();
 
+    bool writeAsync(const void *data, size_t bytes, bool waitForSpace = true);
+    void writeWaitReturn(void *ret, size_t retSize);
+    size_t read(void *data, size_t bytes);
+    void readReturn(const void *data, size_t bytes);
+    bool isEmpty();
 
-
-    void virtual writeAsync(const void *data, size_t bytes);
-    void virtual writeWaitReturn(void *ret, size_t retSize);
-    size_t virtual read(void *data, size_t bytes);
-    void virtual readReturn(const void *data, size_t bytes);
-
-    void virtual flush();
+    int getWriteFd() {return sv[0];}
+    int getReadFd() {return sv[1];}
 
 protected:
     int sv[2];
-    uint32_t sequence;
-
-
+    bool mShutdown;
 };
 
 }
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
deleted file mode 100644
index 0466d8b..0000000
--- a/libs/rs/rsLocklessFifo.cpp
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "rsLocklessFifo.h"
-#include "utils/Timers.h"
-#include "utils/StopWatch.h"
-
-using namespace android;
-using namespace android::renderscript;
-
-LocklessCommandFifo::LocklessCommandFifo() : mBuffer(0), mInitialized(false) {
-    mTimeoutCallback = NULL;
-    mTimeoutCallbackData = NULL;
-    mTimeoutWait = 0;
-}
-
-LocklessCommandFifo::~LocklessCommandFifo() {
-    if (!mInShutdown && mInitialized) {
-        shutdown();
-    }
-    if (mBuffer) {
-        free(mBuffer);
-    }
-}
-
-void LocklessCommandFifo::shutdown() {
-    mInShutdown = true;
-    mSignalToWorker.set();
-}
-
-bool LocklessCommandFifo::init(uint32_t sizeInBytes) {
-    // Add room for a buffer reset command
-    mBuffer = static_cast<uint8_t *>(malloc(sizeInBytes + 4));
-    if (!mBuffer) {
-        ALOGE("LocklessFifo allocation failure");
-        return false;
-    }
-
-    if (!mSignalToControl.init() || !mSignalToWorker.init()) {
-        ALOGE("Signal setup failed");
-        free(mBuffer);
-        return false;
-    }
-
-    mInShutdown = false;
-    mSize = sizeInBytes;
-    mPut = mBuffer;
-    mGet = mBuffer;
-    mEnd = mBuffer + (sizeInBytes) - 1;
-    //dumpState("init");
-    mInitialized = true;
-    return true;
-}
-
-uint32_t LocklessCommandFifo::getFreeSpace() const {
-    int32_t freeSpace = 0;
-    //dumpState("getFreeSpace");
-
-    if (mPut >= mGet) {
-        freeSpace = mEnd - mPut;
-    } else {
-        freeSpace = mGet - mPut;
-    }
-
-    if (freeSpace < 0) {
-        freeSpace = 0;
-    }
-    return freeSpace;
-}
-
-bool LocklessCommandFifo::isEmpty() const {
-    uint32_t p = android_atomic_acquire_load((int32_t *)&mPut);
-    return ((uint8_t *)p) == mGet;
-}
-
-
-void * LocklessCommandFifo::reserve(uint32_t sizeInBytes) {
-    // Add space for command header and loop token;
-    sizeInBytes += 8;
-
-    //dumpState("reserve");
-    if (getFreeSpace() < sizeInBytes) {
-        makeSpace(sizeInBytes);
-    }
-
-    return mPut + 4;
-}
-
-void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes) {
-    if (mInShutdown) {
-        return;
-    }
-    //dumpState("commit 1");
-    reinterpret_cast<uint16_t *>(mPut)[0] = command;
-    reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
-
-    int32_t s = ((sizeInBytes + 3) & ~3) + 4;
-    android_atomic_add(s, (int32_t *)&mPut);
-    //dumpState("commit 2");
-    mSignalToWorker.set();
-}
-
-void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes) {
-    if (mInShutdown) {
-        return;
-    }
-
-    //char buf[1024];
-    //sprintf(buf, "RenderScript LocklessCommandFifo::commitSync  %p %i  %i", this, command, sizeInBytes);
-    //StopWatch compileTimer(buf);
-    commit(command, sizeInBytes);
-    flush();
-}
-
-void LocklessCommandFifo::flush() {
-    //dumpState("flush 1");
-    while (mPut != mGet) {
-        while (!mSignalToControl.wait(mTimeoutWait)) {
-            if (mTimeoutCallback) {
-                mTimeoutCallback(mTimeoutCallbackData);
-            }
-        }
-    }
-    //dumpState("flush 2");
-}
-
-void LocklessCommandFifo::setTimoutCallback(void (*cbk)(void *), void *data, uint64_t timeout) {
-    mTimeoutCallback = cbk;
-    mTimeoutCallbackData = data;
-    mTimeoutWait = timeout;
-}
-
-bool LocklessCommandFifo::wait(uint64_t timeout) {
-    while (isEmpty() && !mInShutdown) {
-        mSignalToControl.set();
-        return mSignalToWorker.wait(timeout);
-    }
-    return true;
-}
-
-const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData, uint64_t timeout) {
-    while (1) {
-        //dumpState("get");
-        wait(timeout);
-
-        if (isEmpty() || mInShutdown) {
-            *command = 0;
-            *bytesData = 0;
-            return NULL;
-        }
-
-        *command = reinterpret_cast<const uint16_t *>(mGet)[0];
-        *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
-        if (*command) {
-            // non-zero command is valid
-            return mGet+4;
-        }
-
-        // zero command means reset to beginning.
-        mGet = mBuffer;
-    }
-}
-
-void LocklessCommandFifo::next() {
-    uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
-
-    android_atomic_add(((bytes + 3) & ~3) + 4, (int32_t *)&mGet);
-    //mGet += ((bytes + 3) & ~3) + 4;
-    if (isEmpty()) {
-        mSignalToControl.set();
-    }
-    //dumpState("next");
-}
-
-bool LocklessCommandFifo::makeSpaceNonBlocking(uint32_t bytes) {
-    //dumpState("make space non-blocking");
-    if ((mPut+bytes) > mEnd) {
-        // Need to loop regardless of where get is.
-        if ((mGet > mPut) || (mBuffer+4 >= mGet)) {
-            return false;
-        }
-
-        // Toss in a reset then the normal wait for space will do the rest.
-        reinterpret_cast<uint16_t *>(mPut)[0] = 0;
-        reinterpret_cast<uint16_t *>(mPut)[1] = 0;
-        mPut = mBuffer;
-        mSignalToWorker.set();
-    }
-
-    // it will fit here so we just need to wait for space.
-    if (getFreeSpace() < bytes) {
-        return false;
-    }
-
-    return true;
-}
-
-void LocklessCommandFifo::makeSpace(uint32_t bytes) {
-    //dumpState("make space");
-    if ((mPut+bytes) > mEnd) {
-        // Need to loop regardless of where get is.
-        while ((mGet > mPut) || (mBuffer+4 >= mGet)) {
-            usleep(100);
-        }
-
-        // Toss in a reset then the normal wait for space will do the rest.
-        reinterpret_cast<uint16_t *>(mPut)[0] = 0;
-        reinterpret_cast<uint16_t *>(mPut)[1] = 0;
-        mPut = mBuffer;
-        mSignalToWorker.set();
-    }
-
-    // it will fit here so we just need to wait for space.
-    while (getFreeSpace() < bytes) {
-        usleep(100);
-    }
-
-}
-
-void LocklessCommandFifo::dumpState(const char *s) const {
-    ALOGV("%s %p  put %p, get %p,  buf %p,  end %p", s, this, mPut, mGet, mBuffer, mEnd);
-}
-
-void LocklessCommandFifo::printDebugData() const {
-    dumpState("printing fifo debug");
-    const uint32_t *pptr = (const uint32_t *)mGet;
-    pptr -= 8 * 4;
-    if (mGet < mBuffer) {
-        pptr = (const uint32_t *)mBuffer;
-    }
-
-
-    for (int ct=0; ct < 16; ct++) {
-        ALOGV("fifo %p = 0x%08x  0x%08x  0x%08x  0x%08x", pptr, pptr[0], pptr[1], pptr[2], pptr[3]);
-        pptr += 4;
-    }
-
-}
diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h
deleted file mode 100644
index dafc512..0000000
--- a/libs/rs/rsLocklessFifo.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_RS_LOCKLESS_FIFO_H
-#define ANDROID_RS_LOCKLESS_FIFO_H
-
-
-#include "rsUtils.h"
-#include "rsSignal.h"
-
-namespace android {
-namespace renderscript {
-
-
-// A simple FIFO to be used as a producer / consumer between two
-// threads.  One is writer and one is reader.  The common cases
-// will not require locking.  It is not threadsafe for multiple
-// readers or writers by design.
-
-class LocklessCommandFifo {
-public:
-    bool init(uint32_t size);
-    void shutdown();
-    void setTimoutCallback(void (*)(void *), void *, uint64_t timeout);
-
-    void printDebugData() const;
-
-    LocklessCommandFifo();
-    ~LocklessCommandFifo();
-
-protected:
-    uint8_t * volatile mPut;
-    uint8_t * volatile mGet;
-    uint8_t * mBuffer;
-    uint8_t * mEnd;
-    uint8_t mSize;
-    bool mInShutdown;
-    bool mInitialized;
-
-    Signal mSignalToWorker;
-    Signal mSignalToControl;
-
-public:
-    void * reserve(uint32_t bytes);
-    void commit(uint32_t command, uint32_t bytes);
-    void commitSync(uint32_t command, uint32_t bytes);
-
-    void flush();
-    bool wait(uint64_t timeout = 0);
-
-    const void * get(uint32_t *command, uint32_t *bytesData, uint64_t timeout = 0);
-    void next();
-
-    void makeSpace(uint32_t bytes);
-    bool makeSpaceNonBlocking(uint32_t bytes);
-
-    bool isEmpty() const;
-    uint32_t getFreeSpace() const;
-
-private:
-    void dumpState(const char *) const;
-
-    void (*mTimeoutCallback)(void *);
-    void * mTimeoutCallbackData;
-    uint64_t mTimeoutWait;
-};
-
-
-}
-}
-#endif
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 0fc73fb..166b5d3 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -23,20 +23,18 @@
 // ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
 
 // An element is a group of Components that occupies one cell in a structure.
 class Mesh : public ObjectBase {
 public:
-    Mesh(Context *);
-    Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
-    ~Mesh();
-
-    virtual void serialize(OStream *stream) const;
-    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
-    static Mesh *createFromStream(Context *rsc, IStream *stream);
-    void init();
-
     struct Hal {
         mutable void *drv;
 
@@ -57,6 +55,15 @@
     };
     Hal mHal;
 
+    Mesh(Context *);
+    Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
+    ~Mesh();
+
+    virtual void serialize(OStream *stream) const;
+    virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
+    static Mesh *createFromStream(Context *rsc, IStream *stream);
+    void init();
+
     void setVertexBuffer(Allocation *vb, uint32_t index) {
         mVertexBuffers[index].set(vb);
         mHal.state.vertexBuffers[index] = vb;
diff --git a/libs/rs/rsPath.cpp b/libs/rs/rsPath.cpp
new file mode 100644
index 0000000..c4f4978
--- /dev/null
+++ b/libs/rs/rsPath.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Path::Path(Context *rsc) : ObjectBase(rsc) {
+}
+
+Path::Path(Context *rsc, RsPathPrimitive pp, bool isStatic,
+                      Allocation *vtx, Allocation *loops, float quality)
+: ObjectBase(rsc) {
+
+    memset(&mHal, 0, sizeof(mHal));
+    mHal.state.quality = quality;
+    mHal.state.primitive = pp;
+
+    //LOGE("i1");
+    rsc->mHal.funcs.path.initStatic(rsc, this, vtx, loops);
+
+    //LOGE("i2");
+}
+
+Path::Path(Context *rsc, uint32_t vertexBuffersCount, uint32_t primitivesCount)
+: ObjectBase(rsc) {
+
+}
+
+Path::~Path() {
+
+}
+
+
+void Path::rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc) {
+
+    for (uint32_t i=0; i < num; i++) {
+
+    }
+
+}
+
+void Path::render(Context *rsc) {
+}
+
+void Path::serialize(OStream *stream) const {
+
+}
+
+RsA3DClassID Path::getClassId() const {
+    return RS_A3D_CLASS_ID_UNKNOWN;
+}
+
+namespace android {
+namespace renderscript {
+
+RsPath rsi_PathCreate(Context *rsc, RsPathPrimitive pp, bool isStatic,
+                      RsAllocation vtx, RsAllocation loops, float quality) {
+    return new Path(rsc, pp, isStatic, (Allocation *)vtx, (Allocation *)loops, quality);
+}
+
+}
+}
diff --git a/libs/rs/rsPath.h b/libs/rs/rsPath.h
new file mode 100644
index 0000000..dac795e
--- /dev/null
+++ b/libs/rs/rsPath.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_PATH_H
+#define ANDROID_RS_PATH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Path : public ObjectBase {
+public:
+    struct {
+        mutable void * drv;
+
+        struct State {
+            RsPathPrimitive primitive;
+            float quality;
+        };
+        State state;
+    } mHal;
+
+    Path(Context *);
+    Path(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
+    Path(Context *, RsPathPrimitive pp, bool isStatic, Allocation *vtx, Allocation *loop, float q);
+
+    ~Path();
+
+    void render(Context *);
+    virtual void serialize(OStream *stream) const;
+    virtual RsA3DClassID getClassId() const;
+
+private:
+
+
+    typedef struct {
+        float x[4];
+        float y[4];
+    } BezierSegment_t;
+
+    bool subdivideCheck(const BezierSegment_t *s, float u1, float u2);
+
+    void rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc);
+
+
+};
+
+}
+}
+#endif //ANDROID_RS_PATH_H
+
+
+
diff --git a/libs/rs/rsRuntime.h b/libs/rs/rsRuntime.h
index cb962a8..3bded62 100644
--- a/libs/rs/rsRuntime.h
+++ b/libs/rs/rsRuntime.h
@@ -30,6 +30,8 @@
 //////////////////////////////////////////////////////////////////////////////
 
 void rsrBindTexture(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *);
+void rsrBindConstant(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *);
+void rsrBindConstant(Context *, Script *, ProgramVertex*, uint32_t slot, Allocation *);
 void rsrBindSampler(Context *, Script *, ProgramFragment *, uint32_t slot, Sampler *);
 void rsrBindProgramStore(Context *, Script *, ProgramStore *);
 void rsrBindProgramFragment(Context *, Script *, ProgramFragment *);
@@ -68,6 +70,7 @@
 void rsrDrawSpriteScreenspace(Context *, Script *,
                               float x, float y, float z, float w, float h);
 void rsrDrawRect(Context *, Script *, float x1, float y1, float x2, float y2, float z);
+void rsrDrawPath(Context *, Script *, Path *);
 void rsrDrawMesh(Context *, Script *, Mesh *);
 void rsrDrawMeshPrimitive(Context *, Script *, Mesh *, uint32_t primIndex);
 void rsrDrawMeshPrimitiveRange(Context *, Script *, Mesh *,
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index afc8ba0..b4eb995 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -206,7 +206,6 @@
         return false;
     }
 
-    rsAssert(bcWrapper.getHeaderVersion() == 0);
     if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
         sdkVersion = bcWrapper.getTargetAPI();
     }
@@ -323,7 +322,7 @@
 
     if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) {
         // Error during compile, destroy s and return null.
-        delete s;
+        ObjectBase::checkDelete(s);
         return NULL;
     }
 
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 7964792..97469d3 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -50,6 +50,18 @@
     pf->bindTexture(rsc, slot, a);
 }
 
+void rsrBindConstant(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Allocation *a) {
+    CHECK_OBJ_OR_NULL(a);
+    CHECK_OBJ(pf);
+    pf->bindAllocation(rsc, a, slot);
+}
+
+void rsrBindConstant(Context *rsc, Script *sc, ProgramVertex *pv, uint32_t slot, Allocation *a) {
+    CHECK_OBJ_OR_NULL(a);
+    CHECK_OBJ(pv);
+    pv->bindAllocation(rsc, a, slot);
+}
+
 void rsrBindSampler(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Sampler *s) {
     CHECK_OBJ_OR_NULL(vs);
     CHECK_OBJ(vpf);
@@ -200,6 +212,14 @@
     rsrDrawQuad(rsc, sc, x1, y2, z, x2, y2, z, x2, y1, z, x1, y1, z);
 }
 
+void rsrDrawPath(Context *rsc, Script *sc, Path *sm) {
+    CHECK_OBJ(sm);
+    if (!rsc->setupCheck()) {
+        return;
+    }
+    sm->render(rsc);
+}
+
 void rsrDrawMesh(Context *rsc, Script *sc, Mesh *sm) {
     CHECK_OBJ(sm);
     if (!rsc->setupCheck()) {
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 8ba1a0e..4f30573 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -18,222 +18,188 @@
 
 #include "rsThreadIO.h"
 
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <fcntl.h>
+#include <poll.h>
+
+
 using namespace android;
 using namespace android::renderscript;
 
-ThreadIO::ThreadIO() : mUsingSocket(false) {
+ThreadIO::ThreadIO() {
+    mRunning = true;
 }
 
 ThreadIO::~ThreadIO() {
 }
 
-void ThreadIO::init(bool useSocket) {
-    mUsingSocket = useSocket;
-    mToCore.init(16 * 1024);
-
-    if (mUsingSocket) {
-        mToClientSocket.init();
-        mToCoreSocket.init();
-    } else {
-        mToClient.init(1024);
-    }
+void ThreadIO::init() {
+    mToClient.init();
+    mToCore.init();
 }
 
 void ThreadIO::shutdown() {
-    //ALOGE("shutdown 1");
+    mRunning = false;
     mToCore.shutdown();
-    //ALOGE("shutdown 2");
-}
-
-void ThreadIO::coreFlush() {
-    //ALOGE("coreFlush 1");
-    if (mUsingSocket) {
-    } else {
-        mToCore.flush();
-    }
-    //ALOGE("coreFlush 2");
 }
 
 void * ThreadIO::coreHeader(uint32_t cmdID, size_t dataLen) {
     //ALOGE("coreHeader %i %i", cmdID, dataLen);
-    if (mUsingSocket) {
-        CoreCmdHeader hdr;
-        hdr.bytes = dataLen;
-        hdr.cmdID = cmdID;
-        mToCoreSocket.writeAsync(&hdr, sizeof(hdr));
-    } else {
-        mCoreCommandSize = dataLen;
-        mCoreCommandID = cmdID;
-        mCoreDataPtr = (uint8_t *)mToCore.reserve(dataLen);
-        mCoreDataBasePtr = mCoreDataPtr;
-    }
-    //ALOGE("coreHeader ret %p", mCoreDataPtr);
-    return mCoreDataPtr;
-}
-
-void ThreadIO::coreData(const void *data, size_t dataLen) {
-    //ALOGE("coreData %p %i", data, dataLen);
-    mToCoreSocket.writeAsync(data, dataLen);
-    //ALOGE("coreData ret %p", mCoreDataPtr);
+    CoreCmdHeader *hdr = (CoreCmdHeader *)&mSendBuffer[0];
+    hdr->bytes = dataLen;
+    hdr->cmdID = cmdID;
+    mSendLen = dataLen + sizeof(CoreCmdHeader);
+    //mToCoreSocket.writeAsync(&hdr, sizeof(hdr));
+    //ALOGE("coreHeader ret ");
+    return &mSendBuffer[sizeof(CoreCmdHeader)];
 }
 
 void ThreadIO::coreCommit() {
-    //ALOGE("coreCommit %p %p %i", mCoreDataPtr, mCoreDataBasePtr, mCoreCommandSize);
-    if (mUsingSocket) {
-    } else {
-        rsAssert((size_t)(mCoreDataPtr - mCoreDataBasePtr) <= mCoreCommandSize);
-        mToCore.commit(mCoreCommandID, mCoreCommandSize);
-    }
-    //ALOGE("coreCommit ret");
-}
-
-void ThreadIO::coreCommitSync() {
-    //ALOGE("coreCommitSync %p %p %i", mCoreDataPtr, mCoreDataBasePtr, mCoreCommandSize);
-    if (mUsingSocket) {
-    } else {
-        rsAssert((size_t)(mCoreDataPtr - mCoreDataBasePtr) <= mCoreCommandSize);
-        mToCore.commitSync(mCoreCommandID, mCoreCommandSize);
-    }
-    //ALOGE("coreCommitSync ret");
+    mToCore.writeAsync(&mSendBuffer, mSendLen);
 }
 
 void ThreadIO::clientShutdown() {
-    //ALOGE("coreShutdown 1");
     mToClient.shutdown();
-    //ALOGE("coreShutdown 2");
 }
 
 void ThreadIO::coreSetReturn(const void *data, size_t dataLen) {
-    rsAssert(dataLen <= sizeof(mToCoreRet));
-    memcpy(&mToCoreRet, data, dataLen);
+    uint32_t buf;
+    if (data == NULL) {
+        data = &buf;
+        dataLen = sizeof(buf);
+    }
+
+    mToCore.readReturn(data, dataLen);
 }
 
 void ThreadIO::coreGetReturn(void *data, size_t dataLen) {
-    memcpy(data, &mToCoreRet, dataLen);
+    uint32_t buf;
+    if (data == NULL) {
+        data = &buf;
+        dataLen = sizeof(buf);
+    }
+
+    mToCore.writeWaitReturn(data, dataLen);
 }
 
-void ThreadIO::setTimoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
-    mToCore.setTimoutCallback(cb, dat, timeout);
+void ThreadIO::setTimeoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
+    //mToCore.setTimeoutCallback(cb, dat, timeout);
 }
 
-
-bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand, uint64_t timeToWait) {
+bool ThreadIO::playCoreCommands(Context *con, int waitFd) {
     bool ret = false;
-    uint64_t startTime = con->getTime();
 
-    while (!mToCore.isEmpty() || waitForCommand) {
-        uint32_t cmdID = 0;
-        uint32_t cmdSize = 0;
-        ret = true;
-        if (con->props.mLogTimes) {
-            con->timerSet(Context::RS_TIMER_IDLE);
+    uint8_t buf[2 * 1024];
+    const CoreCmdHeader *cmd = (const CoreCmdHeader *)&buf[0];
+    const void * data = (const void *)&buf[sizeof(CoreCmdHeader)];
+
+    struct pollfd p[2];
+    p[0].fd = mToCore.getReadFd();
+    p[0].events = POLLIN;
+    p[0].revents = 0;
+    p[1].fd = waitFd;
+    p[1].events = POLLIN;
+    p[1].revents = 0;
+    int pollCount = 1;
+    if (waitFd >= 0) {
+        pollCount = 2;
+    }
+
+    if (con->props.mLogTimes) {
+        con->timerSet(Context::RS_TIMER_IDLE);
+    }
+
+    int waitTime = -1;
+    while (mRunning) {
+        int pr = poll(p, pollCount, waitTime);
+        if (pr <= 0) {
+            break;
         }
 
-        uint64_t delay = 0;
-        if (waitForCommand) {
-            delay = timeToWait - (con->getTime() - startTime);
-            if (delay > timeToWait) {
-                delay = 0;
+        if (p[0].revents) {
+            size_t r = mToCore.read(&buf[0], sizeof(CoreCmdHeader));
+            mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes);
+
+            if (r != sizeof(CoreCmdHeader)) {
+                // exception or timeout occurred.
+                break;
+            }
+
+            ret = true;
+            if (con->props.mLogTimes) {
+                con->timerSet(Context::RS_TIMER_INTERNAL);
+            }
+            //ALOGV("playCoreCommands 3 %i %i", cmd->cmdID, cmd->bytes);
+
+            if (cmd->cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
+                rsAssert(cmd->cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
+                ALOGE("playCoreCommands error con %p, cmd %i", con, cmd->cmdID);
+            }
+            gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes);
+
+            if (con->props.mLogTimes) {
+                con->timerSet(Context::RS_TIMER_IDLE);
+            }
+
+            if (waitFd < 0) {
+                // If we don't have a secondary wait object we should stop blocking now
+                // that at least one command has been processed.
+                waitTime = 0;
             }
         }
-        const void * data = mToCore.get(&cmdID, &cmdSize, delay);
-        if (!cmdSize) {
-            // exception or timeout occurred.
-            return false;
-        }
-        if (con->props.mLogTimes) {
-            con->timerSet(Context::RS_TIMER_INTERNAL);
-        }
-        waitForCommand = false;
-        //ALOGV("playCoreCommands 3 %i %i", cmdID, cmdSize);
 
-        if (cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
-            rsAssert(cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
-            ALOGE("playCoreCommands error con %p, cmd %i", con, cmdID);
-            mToCore.printDebugData();
+        if (p[1].revents && !p[0].revents) {
+            // We want to finish processing fifo events before processing the vsync.
+            // Otherwise we can end up falling behind and having tremendous lag.
+            break;
         }
-        gPlaybackFuncs[cmdID](con, data, cmdSize << 2);
-        mToCore.next();
     }
     return ret;
 }
 
 RsMessageToClientType ThreadIO::getClientHeader(size_t *receiveLen, uint32_t *usrID) {
-    if (mUsingSocket) {
-        mToClientSocket.read(&mLastClientHeader, sizeof(mLastClientHeader));
-    } else {
-        size_t bytesData = 0;
-        const uint32_t *d = (const uint32_t *)mToClient.get(&mLastClientHeader.cmdID, (uint32_t*)&bytesData);
-        if (bytesData >= sizeof(uint32_t)) {
-            mLastClientHeader.userID = d[0];
-            mLastClientHeader.bytes = bytesData - sizeof(uint32_t);
-        } else {
-            mLastClientHeader.userID = 0;
-            mLastClientHeader.bytes = 0;
-        }
-    }
+    //ALOGE("getClientHeader");
+    mToClient.read(&mLastClientHeader, sizeof(mLastClientHeader));
+
     receiveLen[0] = mLastClientHeader.bytes;
     usrID[0] = mLastClientHeader.userID;
+    //ALOGE("getClientHeader %i %i %i", mLastClientHeader.cmdID, usrID[0], receiveLen[0]);
     return (RsMessageToClientType)mLastClientHeader.cmdID;
 }
 
 RsMessageToClientType ThreadIO::getClientPayload(void *data, size_t *receiveLen,
                                 uint32_t *usrID, size_t bufferLen) {
+    //ALOGE("getClientPayload");
     receiveLen[0] = mLastClientHeader.bytes;
     usrID[0] = mLastClientHeader.userID;
     if (bufferLen < mLastClientHeader.bytes) {
         return RS_MESSAGE_TO_CLIENT_RESIZE;
     }
-    if (mUsingSocket) {
-        if (receiveLen[0]) {
-            mToClientSocket.read(data, receiveLen[0]);
-        }
-        return (RsMessageToClientType)mLastClientHeader.cmdID;
-    } else {
-        uint32_t bytesData = 0;
-        uint32_t commandID = 0;
-        const uint32_t *d = (const uint32_t *)mToClient.get(&commandID, &bytesData);
-        //ALOGE("getMessageToClient 3    %i  %i", commandID, bytesData);
-        //ALOGE("getMessageToClient  %i %i", commandID, *subID);
-        if (bufferLen >= receiveLen[0]) {
-            memcpy(data, d+1, receiveLen[0]);
-            mToClient.next();
-            return (RsMessageToClientType)commandID;
-        }
+    if (receiveLen[0]) {
+        mToClient.read(data, receiveLen[0]);
     }
-    return RS_MESSAGE_TO_CLIENT_RESIZE;
+    //ALOGE("getClientPayload x");
+    return (RsMessageToClientType)mLastClientHeader.cmdID;
 }
 
 bool ThreadIO::sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data,
                             size_t dataLen, bool waitForSpace) {
+
+    //ALOGE("sendToClient %i %i %i", cmdID, usrID, (int)dataLen);
     ClientCmdHeader hdr;
     hdr.bytes = dataLen;
     hdr.cmdID = cmdID;
     hdr.userID = usrID;
-    if (mUsingSocket) {
-        mToClientSocket.writeAsync(&hdr, sizeof(hdr));
-        if (dataLen) {
-            mToClientSocket.writeAsync(data, dataLen);
-        }
-        return true;
-    } else {
-        if (!waitForSpace) {
-            if (!mToClient.makeSpaceNonBlocking(dataLen + sizeof(hdr))) {
-                // Not enough room, and not waiting.
-                return false;
-            }
-        }
 
-        //ALOGE("sendMessageToClient 2");
-        uint32_t *p = (uint32_t *)mToClient.reserve(dataLen + sizeof(usrID));
-        p[0] = usrID;
-        if (dataLen > 0) {
-            memcpy(p+1, data, dataLen);
-        }
-        mToClient.commit(cmdID, dataLen + sizeof(usrID));
-        //ALOGE("sendMessageToClient 3");
-        return true;
+    mToClient.writeAsync(&hdr, sizeof(hdr));
+    if (dataLen) {
+        mToClient.writeAsync(data, dataLen);
     }
-    return false;
+
+    //ALOGE("sendToClient x");
+    return true;
 }
 
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index ebce0ab..62e3e33 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -18,7 +18,6 @@
 #define ANDROID_RS_THREAD_IO_H
 
 #include "rsUtils.h"
-#include "rsLocklessFifo.h"
 #include "rsFifoSocket.h"
 
 // ---------------------------------------------------------------------------
@@ -32,23 +31,17 @@
     ThreadIO();
     ~ThreadIO();
 
-    void init(bool useSocket = false);
+    void init();
     void shutdown();
 
     // Plays back commands from the client.
     // Returns true if any commands were processed.
-    bool playCoreCommands(Context *con, bool waitForCommand, uint64_t timeToWait);
+    bool playCoreCommands(Context *con, int waitFd);
 
-    void setTimoutCallback(void (*)(void *), void *, uint64_t timeout);
-    //LocklessCommandFifo mToCore;
+    void setTimeoutCallback(void (*)(void *), void *, uint64_t timeout);
 
-
-
-    void coreFlush();
     void * coreHeader(uint32_t, size_t dataLen);
-    void coreData(const void *data, size_t dataLen);
     void coreCommit();
-    void coreCommitSync();
     void coreSetReturn(const void *data, size_t dataLen);
     void coreGetReturn(void *data, size_t dataLen);
 
@@ -71,20 +64,16 @@
     } ClientCmdHeader;
     ClientCmdHeader mLastClientHeader;
 
-    size_t mCoreCommandSize;
-    uint32_t mCoreCommandID;
-    uint8_t * mCoreDataPtr;
-    uint8_t * mCoreDataBasePtr;
+    bool mRunning;
 
-    bool mUsingSocket;
-    LocklessCommandFifo mToClient;
-    LocklessCommandFifo mToCore;
-
-    FifoSocket mToClientSocket;
-    FifoSocket mToCoreSocket;
+    FifoSocket mToClient;
+    FifoSocket mToCore;
 
     intptr_t mToCoreRet;
 
+    size_t mSendLen;
+    uint8_t mSendBuffer[2 * 1024];
+
 };
 
 
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 7966470..70ab7b7 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -46,12 +46,8 @@
         delete [] mLODs;
         mLODs = NULL;
     }
-    mDimX = 0;
-    mDimY = 0;
-    mDimZ = 0;
-    mDimLOD = 0;
-    mFaces = false;
     mElement.clear();
+    memset(&mHal, 0, sizeof(mHal));
 }
 
 TypeState::TypeState() {
@@ -62,16 +58,16 @@
 }
 
 size_t Type::getOffsetForFace(uint32_t face) const {
-    rsAssert(mFaces);
+    rsAssert(mHal.state.faces);
     return 0;
 }
 
 void Type::compute() {
     uint32_t oldLODCount = mLODCount;
-    if (mDimLOD) {
-        uint32_t l2x = rsFindHighBit(mDimX) + 1;
-        uint32_t l2y = rsFindHighBit(mDimY) + 1;
-        uint32_t l2z = rsFindHighBit(mDimZ) + 1;
+    if (mHal.state.dimLOD) {
+        uint32_t l2x = rsFindHighBit(mHal.state.dimX) + 1;
+        uint32_t l2y = rsFindHighBit(mHal.state.dimY) + 1;
+        uint32_t l2z = rsFindHighBit(mHal.state.dimZ) + 1;
 
         mLODCount = rsMax(l2x, l2y);
         mLODCount = rsMax(mLODCount, l2z);
@@ -85,9 +81,9 @@
         mLODs = new LOD[mLODCount];
     }
 
-    uint32_t tx = mDimX;
-    uint32_t ty = mDimY;
-    uint32_t tz = mDimZ;
+    uint32_t tx = mHal.state.dimX;
+    uint32_t ty = mHal.state.dimY;
+    uint32_t tz = mHal.state.dimZ;
     size_t offset = 0;
     for (uint32_t lod=0; lod < mLODCount; lod++) {
         mLODs[lod].mX = tx;
@@ -103,10 +99,11 @@
     // At this point the offset is the size of a mipmap chain;
     mMipChainSizeBytes = offset;
 
-    if (mFaces) {
+    if (mHal.state.faces) {
         offset *= 6;
     }
     mTotalSizeBytes = offset;
+    mHal.state.element = mElement.get();
 }
 
 uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const {
@@ -127,7 +124,8 @@
     return offset;
 }
 
-uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const {
+uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face,
+                                uint32_t x, uint32_t y) const {
     uint32_t offset = mLODs[lod].mOffset;
     offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes();
 
@@ -141,7 +139,12 @@
 void Type::dumpLOGV(const char *prefix) const {
     char buf[1024];
     ObjectBase::dumpLOGV(prefix);
-    ALOGV("%s   Type: x=%zu y=%zu z=%zu mip=%i face=%i", prefix, mDimX, mDimY, mDimZ, mDimLOD, mFaces);
+    ALOGV("%s   Type: x=%u y=%u z=%u mip=%i face=%i", prefix,
+                                                      mHal.state.dimX,
+                                                      mHal.state.dimY,
+                                                      mHal.state.dimZ,
+                                                      mHal.state.dimLOD,
+                                                      mHal.state.faces);
     snprintf(buf, sizeof(buf), "%s element: ", prefix);
     mElement->dumpLOGV(buf);
 }
@@ -155,12 +158,12 @@
 
     mElement->serialize(stream);
 
-    stream->addU32(mDimX);
-    stream->addU32(mDimY);
-    stream->addU32(mDimZ);
+    stream->addU32(mHal.state.dimX);
+    stream->addU32(mHal.state.dimY);
+    stream->addU32(mHal.state.dimZ);
 
-    stream->addU8((uint8_t)(mDimLOD ? 1 : 0));
-    stream->addU8((uint8_t)(mFaces ? 1 : 0));
+    stream->addU8((uint8_t)(mHal.state.dimLOD ? 1 : 0));
+    stream->addU8((uint8_t)(mHal.state.faces ? 1 : 0));
 }
 
 Type *Type::createFromStream(Context *rsc, IStream *stream) {
@@ -232,11 +235,11 @@
     Type *nt = new Type(rsc);
     returnRef.set(nt);
     nt->mElement.set(e);
-    nt->mDimX = dimX;
-    nt->mDimY = dimY;
-    nt->mDimZ = dimZ;
-    nt->mDimLOD = dimLOD;
-    nt->mFaces = dimFaces;
+    nt->mHal.state.dimX = dimX;
+    nt->mHal.state.dimY = dimY;
+    nt->mHal.state.dimZ = dimZ;
+    nt->mHal.state.dimLOD = dimLOD;
+    nt->mHal.state.faces = dimFaces;
     nt->compute();
 
     ObjectBase::asyncLock();
@@ -248,14 +251,14 @@
 
 ObjectBaseRef<Type> Type::cloneAndResize1D(Context *rsc, uint32_t dimX) const {
     return getTypeRef(rsc, mElement.get(), dimX,
-                      mDimY, mDimZ, mDimLOD, mFaces);
+                      mHal.state.dimY, mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces);
 }
 
 ObjectBaseRef<Type> Type::cloneAndResize2D(Context *rsc,
                               uint32_t dimX,
                               uint32_t dimY) const {
     return getTypeRef(rsc, mElement.get(), dimX, dimY,
-                      mDimZ, mDimLOD, mFaces);
+                      mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces);
 }
 
 
@@ -276,8 +279,8 @@
 
 void rsaTypeGetNativeData(RsContext con, RsType type, uint32_t *typeData, uint32_t typeDataSize) {
     rsAssert(typeDataSize == 6);
-    // Pack the data in the follofing way mDimX; mDimY; mDimZ;
-    // mDimLOD; mDimFaces; mElement; into typeData
+    // Pack the data in the follofing way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ;
+    // mHal.state.dimLOD; mHal.state.faces; mElement; into typeData
     Type *t = static_cast<Type *>(type);
 
     (*typeData++) = t->getDimX();
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index bc0d9ff..3878156 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -22,10 +22,35 @@
 // ---------------------------------------------------------------------------
 namespace android {
 namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
 
 class Type : public ObjectBase {
 public:
+    struct Hal {
+        mutable void *drv;
+
+        struct State {
+            const Element * element;
+
+            // Size of the structure in the various dimensions.  A missing Dimension is
+            // specified as a 0 and not a 1.
+            uint32_t dimX;
+            uint32_t dimY;
+            uint32_t dimZ;
+            bool dimLOD;
+            bool faces;
+        };
+        State state;
+    };
+    Hal mHal;
+
     Type * createTex2D(const Element *, size_t w, size_t h, bool mip);
 
     size_t getOffsetForFace(uint32_t face) const;
@@ -34,22 +59,25 @@
     size_t getElementSizeBytes() const {return mElement->getSizeBytes();}
     const Element * getElement() const {return mElement.get();}
 
-    uint32_t getDimX() const {return mDimX;}
-    uint32_t getDimY() const {return mDimY;}
-    uint32_t getDimZ() const {return mDimZ;}
-    uint32_t getDimLOD() const {return mDimLOD;}
-    bool getDimFaces() const {return mFaces;}
+    uint32_t getDimX() const {return mHal.state.dimX;}
+    uint32_t getDimY() const {return mHal.state.dimY;}
+    uint32_t getDimZ() const {return mHal.state.dimZ;}
+    uint32_t getDimLOD() const {return mHal.state.dimLOD;}
+    bool getDimFaces() const {return mHal.state.faces;}
 
     uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;}
     uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;}
     uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;}
 
-    uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
+    uint32_t getLODOffset(uint32_t lod) const {
+        rsAssert(lod < mLODCount); return mLODs[lod].mOffset;
+    }
     uint32_t getLODOffset(uint32_t lod, uint32_t x) const;
     uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const;
     uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
 
-    uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const;
+    uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face,
+                              uint32_t x, uint32_t y) const;
 
     uint32_t getLODCount() const {return mLODCount;}
     bool getIsNp2() const;
@@ -95,14 +123,6 @@
 
     ObjectBaseRef<const Element> mElement;
 
-    // Size of the structure in the various dimensions.  A missing Dimension is
-    // specified as a 0 and not a 1.
-    size_t mDimX;
-    size_t mDimY;
-    size_t mDimZ;
-    bool mDimLOD;
-    bool mFaces;
-
     // count of mipmap levels, 0 indicates no mipmapping
 
     size_t mMipChainSizeBytes;
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index b8d7351..1e222e1 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -29,6 +29,7 @@
 class Allocation;
 class Script;
 class ScriptC;
+class Path;
 class Program;
 class ProgramStore;
 class ProgramRaster;
@@ -114,6 +115,7 @@
                        bool zeroNew);
         void (*syncAll)(const Context *rsc, const Allocation *alloc, RsAllocationUsageType src);
         void (*markDirty)(const Context *rsc, const Allocation *alloc);
+        int32_t (*initSurfaceTexture)(const Context *rsc, const Allocation *alloc);
 
         void (*data1D)(const Context *rsc, const Allocation *alloc,
                        uint32_t xoff, uint32_t lod, uint32_t count,
@@ -189,6 +191,13 @@
     } mesh;
 
     struct {
+        bool (*initStatic)(const Context *rsc, const Path *m, const Allocation *vtx, const Allocation *loops);
+        bool (*initDynamic)(const Context *rsc, const Path *m);
+        void (*draw)(const Context *rsc, const Path *m);
+        void (*destroy)(const Context *rsc, const Path *m);
+    } path;
+
+    struct {
         bool (*init)(const Context *rsc, const Sampler *m);
         void (*destroy)(const Context *rsc, const Sampler *m);
     } sampler;
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 6b84e56..385c8b5 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -256,7 +256,7 @@
                     fprintf(f, "        memcpy(payload, %s, %s_length);\n", vt->name, vt->name);
                     fprintf(f, "        cmd->%s = (", vt->name);
                     printVarType(f, vt);
-                    fprintf(f, ")payload;\n");
+                    fprintf(f, ")(payload - ((uint8_t *)&cmd[1]));\n");
                     fprintf(f, "        payload += %s_length;\n", vt->name);
                     fprintf(f, "    } else {\n");
                     fprintf(f, "        cmd->%s = %s;\n", vt->name, vt->name);
@@ -270,26 +270,19 @@
                 needFlush = 1;
             }
 
+            fprintf(f, "    io->coreCommit();\n");
             if (hasInlineDataPointers(api)) {
-                fprintf(f, "    if (dataSize < 1024) {\n");
-                fprintf(f, "        io->coreCommit();\n");
-                fprintf(f, "    } else {\n");
-                fprintf(f, "        io->coreCommitSync();\n");
+                fprintf(f, "    if (dataSize >= 1024) {\n");
+                fprintf(f, "        io->coreGetReturn(NULL, 0);\n");
                 fprintf(f, "    }\n");
-            } else {
-                fprintf(f, "    io->coreCommit");
-                if (needFlush) {
-                    fprintf(f, "Sync");
-                }
-                fprintf(f, "();\n");
-            }
-
-            if (api->ret.typeName[0]) {
+            } else if (api->ret.typeName[0]) {
                 fprintf(f, "\n    ");
                 printVarType(f, &api->ret);
                 fprintf(f, " ret;\n");
                 fprintf(f, "    io->coreGetReturn(&ret, sizeof(ret));\n");
                 fprintf(f, "    return ret;\n");
+            } else if (needFlush) {
+                fprintf(f, "    io->coreGetReturn(NULL, 0);\n");
             }
         }
         fprintf(f, "};\n\n");
@@ -434,6 +427,7 @@
 
     for (ct=0; ct < apiCount; ct++) {
         const ApiEntry * api = &apis[ct];
+        int needFlush = 0;
 
         if (api->direct) {
             continue;
@@ -444,6 +438,13 @@
         //fprintf(f, "    ALOGE(\"play command %s\\n\");\n", api->name);
         fprintf(f, "    const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
 
+        if (hasInlineDataPointers(api)) {
+            fprintf(f, "    const uint8_t *baseData = 0;\n");
+            fprintf(f, "    if (cmdSizeBytes != sizeof(RS_CMD_%s)) {\n", api->name);
+            fprintf(f, "        baseData = &((const uint8_t *)vp)[sizeof(*cmd)];\n");
+            fprintf(f, "    }\n");
+        }
+
         fprintf(f, "    ");
         if (api->ret.typeName[0]) {
             fprintf(f, "\n    ");
@@ -453,12 +454,31 @@
         fprintf(f, "rsi_%s(con", api->name);
         for (ct2=0; ct2 < api->paramCount; ct2++) {
             const VarType *vt = &api->params[ct2];
-            fprintf(f, ",\n           cmd->%s", vt->name);
+            needFlush += vt->ptrLevel;
+
+            if (hasInlineDataPointers(api) && vt->ptrLevel) {
+                fprintf(f, ",\n           (const %s *)&baseData[(intptr_t)cmd->%s]", vt->typeName, vt->name);
+            } else {
+                fprintf(f, ",\n           cmd->%s", vt->name);
+            }
         }
         fprintf(f, ");\n");
 
-        if (api->ret.typeName[0]) {
+        if (hasInlineDataPointers(api)) {
+            fprintf(f, "    size_t totalSize = 0;\n");
+            for (ct2=0; ct2 < api->paramCount; ct2++) {
+                if (api->params[ct2].ptrLevel) {
+                    fprintf(f, "    totalSize += cmd->%s_length;\n", api->params[ct2].name);
+                }
+            }
+
+            fprintf(f, "    if ((totalSize != 0) && (cmdSizeBytes == sizeof(RS_CMD_%s))) {\n", api->name);
+            fprintf(f, "        con->mIO.coreSetReturn(NULL, 0);\n");
+            fprintf(f, "    }\n");
+        } else if (api->ret.typeName[0]) {
             fprintf(f, "    con->mIO.coreSetReturn(&ret, sizeof(ret));\n");
+        } else if (api->sync || needFlush) {
+            fprintf(f, "    con->mIO.coreSetReturn(NULL, 0);\n");
         }
 
         fprintf(f, "};\n\n");
@@ -466,6 +486,7 @@
 
     for (ct=0; ct < apiCount; ct++) {
         const ApiEntry * api = &apis[ct];
+        int needFlush = 0;
 
         fprintf(f, "void rspr_%s(Context *con, Fifo *f, uint8_t *scratch, size_t scratchSize) {\n", api->name);
 
@@ -475,6 +496,7 @@
 
         for (ct2=0; ct2 < api->paramCount; ct2++) {
             const VarType *vt = &api->params[ct2];
+            needFlush += vt->ptrLevel;
             if (vt->ptrLevel == 1) {
                 fprintf(f, "    cmd.%s = (", vt->name);
                 printVarType(f, vt);
@@ -515,6 +537,8 @@
 
         if (api->ret.typeName[0]) {
             fprintf(f, "    f->readReturn(&ret, sizeof(ret));\n");
+        } else if (needFlush) {
+            fprintf(f, "    f->readReturn(NULL, 0);\n");
         }
 
         fprintf(f, "};\n\n");
diff --git a/libs/rs/scriptc/rs_allocation.rsh b/libs/rs/scriptc/rs_allocation.rsh
index 9ec03bf..a2f69d9 100644
--- a/libs/rs/scriptc/rs_allocation.rsh
+++ b/libs/rs/scriptc/rs_allocation.rsh
@@ -168,5 +168,135 @@
 extern const void * __attribute__((overloadable))
     rsGetElementAt(rs_allocation, uint32_t x, uint32_t y, uint32_t z);
 
+/**
+ * @param a allocation to get data from
+ * @return element describing allocation layout
+ */
+extern rs_element __attribute__((overloadable))
+    rsAllocationGetElement(rs_allocation a);
+
+/**
+ * @param m mesh to get data from
+ * @return number of allocations in the mesh that contain vertex
+ *         data
+ */
+extern uint32_t __attribute__((overloadable))
+    rsMeshGetVertexAllocationCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @return number of primitive groups in the mesh. This would
+ *         include simple primitives as well as allocations
+ *         containing index data
+ */
+extern uint32_t __attribute__((overloadable))
+    rsMeshGetPrimitiveCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the vertex allocation
+ * @return allocation containing vertex data
+ */
+extern rs_allocation __attribute__((overloadable))
+    rsMeshGetVertexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the index allocation
+ * @return allocation containing index data
+ */
+extern rs_allocation __attribute__((overloadable))
+    rsMeshGetIndexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the primitive
+ * @return primitive describing how the mesh is rendered
+ */
+extern rs_primitive __attribute__((overloadable))
+    rsMeshGetPrimitive(rs_mesh m, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @return number of sub-elements in this element
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementCount(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return sub-element in this element at given index
+ */
+extern rs_element __attribute__((overloadable))
+    rsElementGetSubElement(rs_element, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return length of the sub-element name including the null
+ *         terminator (size of buffer needed to write the name)
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementNameLength(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @param name array to store the name into
+ * @param nameLength length of the provided name array
+ * @return number of characters actually written, excluding the
+ *         null terminator
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementName(rs_element e, uint32_t index, char *name, uint32_t nameLength);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return array size of sub-element in this element at given
+ *         index
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementArraySize(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return offset in bytes of sub-element in this element at
+ *         given index
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSubElementOffsetBytes(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @return total size of the element in bytes
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetSizeBytes(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data type
+ */
+extern rs_data_type __attribute__((overloadable))
+    rsElementGetDataType(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data size
+ */
+extern rs_data_kind __attribute__((overloadable))
+    rsElementGetDataKind(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return length of the element vector (for float2, float3,
+ *         etc.)
+ */
+extern uint32_t __attribute__((overloadable))
+    rsElementGetVectorSize(rs_element e);
+
 #endif
 
diff --git a/libs/rs/scriptc/rs_atomic.rsh b/libs/rs/scriptc/rs_atomic.rsh
index 87c6c02..a455edd 100644
--- a/libs/rs/scriptc/rs_atomic.rsh
+++ b/libs/rs/scriptc/rs_atomic.rsh
@@ -242,7 +242,7 @@
  * @return old value
  */
 extern uint32_t __attribute__((overloadable))
-    rsAtomicCas(volatile uint32_t* addr, int32_t compareValue, int32_t newValue);
+    rsAtomicCas(volatile uint32_t* addr, uint32_t compareValue, uint32_t newValue);
 
 #endif //defined(RS_VERSION) && (RS_VERSION >= 14)
 
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index 2581953..7fdebdc 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -22,6 +22,66 @@
  */
 #ifndef __RS_GRAPHICS_RSH__
 #define __RS_GRAPHICS_RSH__
+
+// These are API 15 once it get official
+typedef enum {
+    RS_DEPTH_FUNC_ALWAYS,
+    RS_DEPTH_FUNC_LESS,
+    RS_DEPTH_FUNC_LEQUAL,
+    RS_DEPTH_FUNC_GREATER,
+    RS_DEPTH_FUNC_GEQUAL,
+    RS_DEPTH_FUNC_EQUAL,
+    RS_DEPTH_FUNC_NOTEQUAL,
+
+    RS_DEPTH_FUNC_INVALID = 100,
+} rs_depth_func;
+
+typedef enum {
+    RS_BLEND_SRC_ZERO,                  // 0
+    RS_BLEND_SRC_ONE,                   // 1
+    RS_BLEND_SRC_DST_COLOR,             // 2
+    RS_BLEND_SRC_ONE_MINUS_DST_COLOR,   // 3
+    RS_BLEND_SRC_SRC_ALPHA,             // 4
+    RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_SRC_DST_ALPHA,             // 6
+    RS_BLEND_SRC_ONE_MINUS_DST_ALPHA,   // 7
+    RS_BLEND_SRC_SRC_ALPHA_SATURATE,    // 8
+
+    RS_BLEND_SRC_INVALID = 100,
+} rs_blend_src_func;
+
+typedef enum {
+    RS_BLEND_DST_ZERO,                  // 0
+    RS_BLEND_DST_ONE,                   // 1
+    RS_BLEND_DST_SRC_COLOR,             // 2
+    RS_BLEND_DST_ONE_MINUS_SRC_COLOR,   // 3
+    RS_BLEND_DST_SRC_ALPHA,             // 4
+    RS_BLEND_DST_ONE_MINUS_SRC_ALPHA,   // 5
+    RS_BLEND_DST_DST_ALPHA,             // 6
+    RS_BLEND_DST_ONE_MINUS_DST_ALPHA,   // 7
+
+    RS_BLEND_DST_INVALID = 100,
+} rs_blend_dst_func;
+
+typedef enum {
+    RS_CULL_BACK,
+    RS_CULL_FRONT,
+    RS_CULL_NONE,
+
+    RS_CULL_INVALID = 100,
+} rs_cull_mode;
+
+typedef enum {
+    RS_SAMPLER_NEAREST,
+    RS_SAMPLER_LINEAR,
+    RS_SAMPLER_LINEAR_MIP_LINEAR,
+    RS_SAMPLER_WRAP,
+    RS_SAMPLER_CLAMP,
+    RS_SAMPLER_LINEAR_MIP_NEAREST,
+
+    RS_SAMPLER_INVALID = 100,
+} rs_sampler_value;
+
 #if (defined(RS_VERSION) && (RS_VERSION >= 14))
 /**
  * Set the color target used for all subsequent rendering calls
@@ -82,6 +142,88 @@
 extern void __attribute__((overloadable))
     rsgBindProgramStore(rs_program_store ps);
 
+
+/**
+ * @hide
+ * Get program store depth function
+ *
+ * @param ps
+ */
+extern rs_depth_func __attribute__((overloadable))
+    rsgProgramStoreGetDepthFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetDepthMask(rs_program_store ps);
+/**
+ * @hide
+ * Get program store red component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskR(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store green component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskG(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blur component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskB(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store alpha component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetColorMaskA(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend source function
+ *
+ * @param ps
+ */
+extern rs_blend_src_func __attribute__((overloadable))
+        rsgProgramStoreGetBlendSrcFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend destination function
+ *
+ * @param ps
+ */
+extern rs_blend_dst_func __attribute__((overloadable))
+    rsgProgramStoreGetBlendDstFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store dither state
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramStoreGetDitherEnabled(rs_program_store ps);
+
+
 /**
  * Bind a new ProgramVertex to the rendering context.
  *
@@ -99,6 +241,24 @@
     rsgBindProgramRaster(rs_program_raster pr);
 
 /**
+ * @hide
+ * Get program raster point sprite state
+ *
+ * @param pr
+ */
+extern bool __attribute__((overloadable))
+    rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr);
+
+/**
+ * @hide
+ * Get program raster cull mode
+ *
+ * @param pr
+ */
+extern rs_cull_mode __attribute__((overloadable))
+    rsgProgramRasterGetCullMode(rs_program_raster pr);
+
+/**
  * Bind a new Sampler object to a ProgramFragment.  The sampler will
  * operate on the texture bound at the matching slot.
  *
@@ -108,6 +268,51 @@
     rsgBindSampler(rs_program_fragment, uint slot, rs_sampler);
 
 /**
+ * @hide
+ * Get sampler minification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetMinification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler magnification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetMagnification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap S value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetWrapS(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap T value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+    rsgSamplerGetWrapT(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler anisotropy
+ *
+ * @param pr
+ */
+extern float __attribute__((overloadable))
+    rsgSamplerGetAnisotropy(rs_sampler s);
+
+/**
  * Bind a new Allocation object to a ProgramFragment.  The
  * Allocation must be a valid texture for the Program.  The sampling
  * of the texture will be controled by the Sampler bound at the
@@ -164,6 +369,28 @@
     rsgProgramFragmentConstantColor(rs_program_fragment pf, float r, float g, float b, float a);
 
 /**
+ * Bind a new Allocation object to a ProgramFragment.  The
+ * Allocation must be a valid constant input for the Program.
+ *
+ * @param ps program object
+ * @param slot index of the constant buffer on the program
+ * @param c constants to bind
+ */
+extern void __attribute__((overloadable))
+    rsgBindConstant(rs_program_fragment ps, uint slot, rs_allocation c);
+
+/**
+ * Bind a new Allocation object to a ProgramVertex.  The
+ * Allocation must be a valid constant input for the Program.
+ *
+ * @param pv program object
+ * @param slot index of the constant buffer on the program
+ * @param c constants to bind
+ */
+extern void __attribute__((overloadable))
+    rsgBindConstant(rs_program_vertex pv, uint slot, rs_allocation c);
+
+/**
  * Get the width of the current rendering surface.
  *
  * @return uint
@@ -288,6 +515,9 @@
 extern void __attribute__((overloadable))
     rsgDrawSpriteScreenspace(float x, float y, float z, float w, float h);
 
+extern void __attribute__((overloadable))
+    rsgDrawPath(rs_path p);
+
 /**
  * Draw a mesh using the current context state.  The whole mesh is
  * rendered.
diff --git a/libs/rs/scriptc/rs_object.rsh b/libs/rs/scriptc/rs_object.rsh
index a431219..1fc3f83 100644
--- a/libs/rs/scriptc/rs_object.rsh
+++ b/libs/rs/scriptc/rs_object.rsh
@@ -56,6 +56,11 @@
  * \overload
  */
 extern void __attribute__((overloadable))
+    rsSetObject(rs_path *dst, rs_path src);
+/**
+ * \overload
+ */
+extern void __attribute__((overloadable))
     rsSetObject(rs_mesh *dst, rs_mesh src);
 /**
  * \overload
@@ -114,6 +119,11 @@
  * \overload
  */
 extern void __attribute__((overloadable))
+    rsClearObject(rs_path *dst);
+/**
+ * \overload
+ */
+extern void __attribute__((overloadable))
     rsClearObject(rs_mesh *dst);
 /**
  * \overload
@@ -175,6 +185,11 @@
  * \overload
  */
 extern bool __attribute__((overloadable))
+    rsIsObject(rs_path);
+/**
+ * \overload
+ */
+extern bool __attribute__((overloadable))
     rsIsObject(rs_mesh);
 /**
  * \overload
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 84bca9c..5345a48 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -138,6 +138,12 @@
  */
 typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_mesh;
 /**
+ * \brief Opaque handle to a Renderscript Path object.
+ *
+ * See: android.renderscript.Path
+ */
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_path;
+/**
  * \brief Opaque handle to a Renderscript ProgramFragment object.
  *
  * See: android.renderscript.ProgramFragment
@@ -396,4 +402,96 @@
 
 #endif //defined(RS_VERSION) && (RS_VERSION >= 14)
 
+/**
+ * Describes the way mesh vertex data is interpreted when rendering
+ *
+ **/
+typedef enum {
+    RS_PRIMITIVE_POINT,
+    RS_PRIMITIVE_LINE,
+    RS_PRIMITIVE_LINE_STRIP,
+    RS_PRIMITIVE_TRIANGLE,
+    RS_PRIMITIVE_TRIANGLE_STRIP,
+    RS_PRIMITIVE_TRIANGLE_FAN,
+
+    RS_PRIMITIVE_INVALID = 100,
+} rs_primitive;
+
+/**
+ * \brief Enumeration for possible element data types
+ *
+ * DataType represents the basic type information for a basic element.  The
+ * naming convention follows.  For numeric types it is FLOAT,
+ * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+ * size of the data.  BOOLEAN is a true / false (1,0)
+ * represented in an 8 bit container.  The UNSIGNED variants
+ * with multiple bit definitions are for packed graphical data
+ * formats and represent vectors with per vector member sizes
+ * which are treated as a single unit for packing and alignment
+ * purposes.
+ *
+ * MATRIX the three matrix types contain FLOAT_32 elements and are treated
+ * as 32 bits for alignment purposes.
+ *
+ * RS_* objects.  32 bit opaque handles.
+ */
+typedef enum {
+    RS_TYPE_NONE,
+    //RS_TYPE_FLOAT_16,
+    RS_TYPE_FLOAT_32 = 2,
+    RS_TYPE_FLOAT_64,
+    RS_TYPE_SIGNED_8,
+    RS_TYPE_SIGNED_16,
+    RS_TYPE_SIGNED_32,
+    RS_TYPE_SIGNED_64,
+    RS_TYPE_UNSIGNED_8,
+    RS_TYPE_UNSIGNED_16,
+    RS_TYPE_UNSIGNED_32,
+    RS_TYPE_UNSIGNED_64,
+
+    RS_TYPE_BOOLEAN,
+
+    RS_TYPE_UNSIGNED_5_6_5,
+    RS_TYPE_UNSIGNED_5_5_5_1,
+    RS_TYPE_UNSIGNED_4_4_4_4,
+
+    RS_TYPE_MATRIX_4X4,
+    RS_TYPE_MATRIX_3X3,
+    RS_TYPE_MATRIX_2X2,
+
+    RS_TYPE_ELEMENT = 1000,
+    RS_TYPE_TYPE,
+    RS_TYPE_ALLOCATION,
+    RS_TYPE_SAMPLER,
+    RS_TYPE_SCRIPT,
+    RS_TYPE_MESH,
+    RS_TYPE_PROGRAM_FRAGMENT,
+    RS_TYPE_PROGRAM_VERTEX,
+    RS_TYPE_PROGRAM_RASTER,
+    RS_TYPE_PROGRAM_STORE,
+
+    RS_TYPE_INVALID = 10000,
+} rs_data_type;
+
+/**
+ * \brief Enumeration for possible element data kind
+ *
+ * The special interpretation of the data if required.  This is primarly
+ * useful for graphical data.  USER indicates no special interpretation is
+ * expected.  PIXEL is used in conjunction with the standard data types for
+ * representing texture formats.
+ */
+typedef enum {
+    RS_KIND_USER,
+
+    RS_KIND_PIXEL_L = 7,
+    RS_KIND_PIXEL_A,
+    RS_KIND_PIXEL_LA,
+    RS_KIND_PIXEL_RGB,
+    RS_KIND_PIXEL_RGBA,
+    RS_KIND_PIXEL_DEPTH,
+
+    RS_KIND_INVALID = 100,
+} rs_data_kind;
+
 #endif
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 09cbb31..ecb3fb5 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -7,325 +7,203 @@
 
 //#define LOG_NDEBUG 0
 
-// Log debug messages about channel signalling (send signal, receive signal)
-#define DEBUG_CHANNEL_SIGNALS 0
+// Log debug messages about channel messages (send message, receive message)
+#define DEBUG_CHANNEL_MESSAGES 0
 
 // Log debug messages whenever InputChannel objects are created/destroyed
 #define DEBUG_CHANNEL_LIFECYCLE 0
 
-// Log debug messages about transport actions (initialize, reset, publish, ...)
+// Log debug messages about transport actions
 #define DEBUG_TRANSPORT_ACTIONS 0
 
 
-#include <cutils/ashmem.h>
 #include <cutils/log.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <sys/mman.h>
 #include <ui/InputTransport.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
 
 namespace android {
 
-#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1))
-#define MIN_HISTORY_DEPTH 20
+// Socket buffer size.  The default is typically about 128KB, which is much larger than
+// we really need.  So we make it smaller.  It just needs to be big enough to hold
+// a few dozen large multi-finger motion events in the case where an application gets
+// behind processing touches.
+static const size_t SOCKET_BUFFER_SIZE = 32 * 1024;
 
-// Must be at least sizeof(InputMessage) + sufficient space for pointer data
-static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP(
-        sizeof(InputMessage) + MIN_HISTORY_DEPTH
-                * (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)),
-        4096);
 
-// Signal sent by the producer to the consumer to inform it that a new message is
-// available to be consumed in the shared memory buffer.
-static const char INPUT_SIGNAL_DISPATCH = 'D';
+// --- InputMessage ---
 
-// Signal sent by the consumer to the producer to inform it that it has finished
-// consuming the most recent message and it handled it.
-static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f';
+bool InputMessage::isValid(size_t actualSize) const {
+    if (size() == actualSize) {
+        switch (header.type) {
+        case TYPE_KEY:
+            return true;
+        case TYPE_MOTION:
+            return body.motion.pointerCount > 0
+                    && body.motion.pointerCount <= MAX_POINTERS;
+        case TYPE_FINISHED:
+            return true;
+        }
+    }
+    return false;
+}
 
-// Signal sent by the consumer to the producer to inform it that it has finished
-// consuming the most recent message but it did not handle it.
-static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u';
+size_t InputMessage::size() const {
+    switch (header.type) {
+    case TYPE_KEY:
+        return sizeof(Header) + body.key.size();
+    case TYPE_MOTION:
+        return sizeof(Header) + body.motion.size();
+    case TYPE_FINISHED:
+        return sizeof(Header) + body.finished.size();
+    }
+    return sizeof(Header);
+}
 
 
 // --- InputChannel ---
 
-InputChannel::InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
-        int32_t sendPipeFd) :
-        mName(name), mAshmemFd(ashmemFd), mReceivePipeFd(receivePipeFd), mSendPipeFd(sendPipeFd) {
+InputChannel::InputChannel(const String8& name, int fd) :
+        mName(name), mFd(fd) {
 #if DEBUG_CHANNEL_LIFECYCLE
-    ALOGD("Input channel constructed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
-            mName.string(), ashmemFd, receivePipeFd, sendPipeFd);
+    ALOGD("Input channel constructed: name='%s', fd=%d",
+            mName.string(), fd);
 #endif
 
-    int result = fcntl(mReceivePipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make receive pipe "
-            "non-blocking.  errno=%d", mName.string(), errno);
-
-    result = fcntl(mSendPipeFd, F_SETFL, O_NONBLOCK);
-    LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make send pipe "
+    int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
+    LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
             "non-blocking.  errno=%d", mName.string(), errno);
 }
 
 InputChannel::~InputChannel() {
 #if DEBUG_CHANNEL_LIFECYCLE
-    ALOGD("Input channel destroyed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
-            mName.string(), mAshmemFd, mReceivePipeFd, mSendPipeFd);
+    ALOGD("Input channel destroyed: name='%s', fd=%d",
+            mName.string(), mFd);
 #endif
 
-    ::close(mAshmemFd);
-    ::close(mReceivePipeFd);
-    ::close(mSendPipeFd);
+    ::close(mFd);
 }
 
 status_t InputChannel::openInputChannelPair(const String8& name,
         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
-    status_t result;
-
-    String8 ashmemName("InputChannel ");
-    ashmemName.append(name);
-    int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
-    if (serverAshmemFd < 0) {
-        result = -errno;
-        ALOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
+    int sockets[2];
+    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
+        status_t result = -errno;
+        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
                 name.string(), errno);
-    } else {
-        result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE);
-        if (result < 0) {
-            ALOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.",
-                    name.string(), result, serverAshmemFd);
-        } else {
-            // Dup the file descriptor because the server and client input channel objects that
-            // are returned may have different lifetimes but they share the same shared memory region.
-            int clientAshmemFd;
-            clientAshmemFd = dup(serverAshmemFd);
-            if (clientAshmemFd < 0) {
-                result = -errno;
-                ALOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d",
-                        name.string(), errno);
-            } else {
-                int forward[2];
-                if (pipe(forward)) {
-                    result = -errno;
-                    ALOGE("channel '%s' ~ Could not create forward pipe.  errno=%d",
-                            name.string(), errno);
-                } else {
-                    int reverse[2];
-                    if (pipe(reverse)) {
-                        result = -errno;
-                        ALOGE("channel '%s' ~ Could not create reverse pipe.  errno=%d",
-                                name.string(), errno);
-                    } else {
-                        String8 serverChannelName = name;
-                        serverChannelName.append(" (server)");
-                        outServerChannel = new InputChannel(serverChannelName,
-                                serverAshmemFd, reverse[0], forward[1]);
-
-                        String8 clientChannelName = name;
-                        clientChannelName.append(" (client)");
-                        outClientChannel = new InputChannel(clientChannelName,
-                                clientAshmemFd, forward[0], reverse[1]);
-                        return OK;
-                    }
-                    ::close(forward[0]);
-                    ::close(forward[1]);
-                }
-                ::close(clientAshmemFd);
-            }
-        }
-        ::close(serverAshmemFd);
+        outServerChannel.clear();
+        outClientChannel.clear();
+        return result;
     }
 
-    outServerChannel.clear();
-    outClientChannel.clear();
-    return result;
+    int bufferSize = SOCKET_BUFFER_SIZE;
+    setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
+    setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
+    setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
+    setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
+
+    String8 serverChannelName = name;
+    serverChannelName.append(" (server)");
+    outServerChannel = new InputChannel(serverChannelName, sockets[0]);
+
+    String8 clientChannelName = name;
+    clientChannelName.append(" (client)");
+    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
+    return OK;
 }
 
-status_t InputChannel::sendSignal(char signal) {
+status_t InputChannel::sendMessage(const InputMessage* msg) {
+    size_t msgLength = msg->size();
     ssize_t nWrite;
     do {
-        nWrite = ::write(mSendPipeFd, & signal, 1);
+        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
     } while (nWrite == -1 && errno == EINTR);
 
-    if (nWrite == 1) {
-#if DEBUG_CHANNEL_SIGNALS
-        ALOGD("channel '%s' ~ sent signal '%c'", mName.string(), signal);
+    if (nWrite < 0) {
+        int error = errno;
+#if DEBUG_CHANNEL_MESSAGES
+        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
+                msg->header.type, error);
 #endif
-        return OK;
+        if (error == EAGAIN || error == EWOULDBLOCK) {
+            return WOULD_BLOCK;
+        }
+        if (error == EPIPE || error == ENOTCONN) {
+            return DEAD_OBJECT;
+        }
+        return -error;
     }
 
-#if DEBUG_CHANNEL_SIGNALS
-    ALOGD("channel '%s' ~ error sending signal '%c', errno=%d", mName.string(), signal, errno);
-#endif
-    return -errno;
-}
-
-status_t InputChannel::receiveSignal(char* outSignal) {
-    ssize_t nRead;
-    do {
-        nRead = ::read(mReceivePipeFd, outSignal, 1);
-    } while (nRead == -1 && errno == EINTR);
-
-    if (nRead == 1) {
-#if DEBUG_CHANNEL_SIGNALS
-        ALOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal);
-#endif
-        return OK;
-    }
-
-    if (nRead == 0) { // check for EOF
-#if DEBUG_CHANNEL_SIGNALS
-        ALOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string());
+    if (size_t(nWrite) != msgLength) {
+#if DEBUG_CHANNEL_MESSAGES
+        ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
+                mName.string(), msg->header.type);
 #endif
         return DEAD_OBJECT;
     }
 
-    if (errno == EAGAIN) {
-#if DEBUG_CHANNEL_SIGNALS
-        ALOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
+#if DEBUG_CHANNEL_MESSAGES
+    ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
 #endif
-        return WOULD_BLOCK;
+    return OK;
+}
+
+status_t InputChannel::receiveMessage(InputMessage* msg) {
+    ssize_t nRead;
+    do {
+        nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
+    } while (nRead == -1 && errno == EINTR);
+
+    if (nRead < 0) {
+        int error = errno;
+#if DEBUG_CHANNEL_MESSAGES
+        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);
+#endif
+        if (error == EAGAIN || error == EWOULDBLOCK) {
+            return WOULD_BLOCK;
+        }
+        if (error == EPIPE || error == ENOTCONN) {
+            return DEAD_OBJECT;
+        }
+        return -error;
     }
 
-#if DEBUG_CHANNEL_SIGNALS
-    ALOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno);
+    if (nRead == 0) { // check for EOF
+#if DEBUG_CHANNEL_MESSAGES
+        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
 #endif
-    return -errno;
+        return DEAD_OBJECT;
+    }
+
+    if (!msg->isValid(nRead)) {
+#if DEBUG_CHANNEL_MESSAGES
+        ALOGD("channel '%s' ~ received invalid message", mName.string());
+#endif
+        return BAD_VALUE;
+    }
+
+#if DEBUG_CHANNEL_MESSAGES
+    ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);
+#endif
+    return OK;
 }
 
 
 // --- InputPublisher ---
 
 InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
-        mChannel(channel), mSharedMessage(NULL),
-        mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
-        mMotionEventSampleDataTail(NULL) {
+        mChannel(channel) {
 }
 
 InputPublisher::~InputPublisher() {
-    reset();
-
-    if (mSharedMessage) {
-        munmap(mSharedMessage, mAshmemSize);
-    }
-}
-
-status_t InputPublisher::initialize() {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' publisher ~ initialize",
-            mChannel->getName().string());
-#endif
-
-    int ashmemFd = mChannel->getAshmemFd();
-    int result = ashmem_get_size_region(ashmemFd);
-    if (result < 0) {
-        ALOGE("channel '%s' publisher ~ Error %d getting size of ashmem fd %d.",
-                mChannel->getName().string(), result, ashmemFd);
-        return UNKNOWN_ERROR;
-    }
-    mAshmemSize = (size_t) result;
-
-    mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
-            PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
-    if (! mSharedMessage) {
-        ALOGE("channel '%s' publisher ~ mmap failed on ashmem fd %d.",
-                mChannel->getName().string(), ashmemFd);
-        return NO_MEMORY;
-    }
-
-    mPinned = true;
-    mSharedMessage->consumed = false;
-
-    return reset();
-}
-
-status_t InputPublisher::reset() {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' publisher ~ reset",
-        mChannel->getName().string());
-#endif
-
-    if (mPinned) {
-        // Destroy the semaphore since we are about to unpin the memory region that contains it.
-        int result;
-        if (mSemaphoreInitialized) {
-            if (mSharedMessage->consumed) {
-                result = sem_post(& mSharedMessage->semaphore);
-                if (result < 0) {
-                    ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
-                            mChannel->getName().string(), errno);
-                    return UNKNOWN_ERROR;
-                }
-            }
-
-            result = sem_destroy(& mSharedMessage->semaphore);
-            if (result < 0) {
-                ALOGE("channel '%s' publisher ~ Error %d in sem_destroy.",
-                        mChannel->getName().string(), errno);
-                return UNKNOWN_ERROR;
-            }
-
-            mSemaphoreInitialized = false;
-        }
-
-        // Unpin the region since we no longer care about its contents.
-        int ashmemFd = mChannel->getAshmemFd();
-        result = ashmem_unpin_region(ashmemFd, 0, 0);
-        if (result < 0) {
-            ALOGE("channel '%s' publisher ~ Error %d unpinning ashmem fd %d.",
-                    mChannel->getName().string(), result, ashmemFd);
-            return UNKNOWN_ERROR;
-        }
-
-        mPinned = false;
-    }
-
-    mMotionEventSampleDataTail = NULL;
-    mWasDispatched = false;
-    return OK;
-}
-
-status_t InputPublisher::publishInputEvent(
-        int32_t type,
-        int32_t deviceId,
-        int32_t source) {
-    if (mPinned) {
-        ALOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has "
-                "not yet been reset.", mChannel->getName().string());
-        return INVALID_OPERATION;
-    }
-
-    // Pin the region.
-    // We do not check for ASHMEM_NOT_PURGED because we don't care about the previous
-    // contents of the buffer so it does not matter whether it was purged in the meantime.
-    int ashmemFd = mChannel->getAshmemFd();
-    int result = ashmem_pin_region(ashmemFd, 0, 0);
-    if (result < 0) {
-        ALOGE("channel '%s' publisher ~ Error %d pinning ashmem fd %d.",
-                mChannel->getName().string(), result, ashmemFd);
-        return UNKNOWN_ERROR;
-    }
-
-    mPinned = true;
-
-    result = sem_init(& mSharedMessage->semaphore, 1, 1);
-    if (result < 0) {
-        ALOGE("channel '%s' publisher ~ Error %d in sem_init.",
-                mChannel->getName().string(), errno);
-        return UNKNOWN_ERROR;
-    }
-
-    mSemaphoreInitialized = true;
-
-    mSharedMessage->consumed = false;
-    mSharedMessage->type = type;
-    mSharedMessage->deviceId = deviceId;
-    mSharedMessage->source = source;
-    return OK;
 }
 
 status_t InputPublisher::publishKeyEvent(
+        uint32_t seq,
         int32_t deviceId,
         int32_t source,
         int32_t action,
@@ -337,31 +215,37 @@
         nsecs_t downTime,
         nsecs_t eventTime) {
 #if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=0x%x, "
+    ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
             "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
             "downTime=%lld, eventTime=%lld",
-            mChannel->getName().string(),
+            mChannel->getName().string(), seq,
             deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
             downTime, eventTime);
 #endif
 
-    status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source);
-    if (result < 0) {
-        return result;
+    if (!seq) {
+        ALOGE("Attempted to publish a key event with sequence number 0.");
+        return BAD_VALUE;
     }
 
-    mSharedMessage->key.action = action;
-    mSharedMessage->key.flags = flags;
-    mSharedMessage->key.keyCode = keyCode;
-    mSharedMessage->key.scanCode = scanCode;
-    mSharedMessage->key.metaState = metaState;
-    mSharedMessage->key.repeatCount = repeatCount;
-    mSharedMessage->key.downTime = downTime;
-    mSharedMessage->key.eventTime = eventTime;
-    return OK;
+    InputMessage msg;
+    msg.header.type = InputMessage::TYPE_KEY;
+    msg.body.key.seq = seq;
+    msg.body.key.deviceId = deviceId;
+    msg.body.key.source = source;
+    msg.body.key.action = action;
+    msg.body.key.flags = flags;
+    msg.body.key.keyCode = keyCode;
+    msg.body.key.scanCode = scanCode;
+    msg.body.key.metaState = metaState;
+    msg.body.key.repeatCount = repeatCount;
+    msg.body.key.downTime = downTime;
+    msg.body.key.eventTime = eventTime;
+    return mChannel->sendMessage(&msg);
 }
 
 status_t InputPublisher::publishMotionEvent(
+        uint32_t seq,
         int32_t deviceId,
         int32_t source,
         int32_t action,
@@ -379,349 +263,349 @@
         const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
 #if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
+    ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
             "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
             "xOffset=%f, yOffset=%f, "
             "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
             "pointerCount=%d",
-            mChannel->getName().string(),
+            mChannel->getName().string(), seq,
             deviceId, source, action, flags, edgeFlags, metaState, buttonState,
             xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
 #endif
 
+    if (!seq) {
+        ALOGE("Attempted to publish a motion event with sequence number 0.");
+        return BAD_VALUE;
+    }
+
     if (pointerCount > MAX_POINTERS || pointerCount < 1) {
         ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
                 mChannel->getName().string(), pointerCount);
         return BAD_VALUE;
     }
 
-    status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source);
-    if (result < 0) {
-        return result;
-    }
-
-    mSharedMessage->motion.action = action;
-    mSharedMessage->motion.flags = flags;
-    mSharedMessage->motion.edgeFlags = edgeFlags;
-    mSharedMessage->motion.metaState = metaState;
-    mSharedMessage->motion.buttonState = buttonState;
-    mSharedMessage->motion.xOffset = xOffset;
-    mSharedMessage->motion.yOffset = yOffset;
-    mSharedMessage->motion.xPrecision = xPrecision;
-    mSharedMessage->motion.yPrecision = yPrecision;
-    mSharedMessage->motion.downTime = downTime;
-    mSharedMessage->motion.pointerCount = pointerCount;
-
-    mSharedMessage->motion.sampleCount = 1;
-    mSharedMessage->motion.sampleData[0].eventTime = eventTime;
-
+    InputMessage msg;
+    msg.header.type = InputMessage::TYPE_MOTION;
+    msg.body.motion.seq = seq;
+    msg.body.motion.deviceId = deviceId;
+    msg.body.motion.source = source;
+    msg.body.motion.action = action;
+    msg.body.motion.flags = flags;
+    msg.body.motion.edgeFlags = edgeFlags;
+    msg.body.motion.metaState = metaState;
+    msg.body.motion.buttonState = buttonState;
+    msg.body.motion.xOffset = xOffset;
+    msg.body.motion.yOffset = yOffset;
+    msg.body.motion.xPrecision = xPrecision;
+    msg.body.motion.yPrecision = yPrecision;
+    msg.body.motion.downTime = downTime;
+    msg.body.motion.eventTime = eventTime;
+    msg.body.motion.pointerCount = pointerCount;
     for (size_t i = 0; i < pointerCount; i++) {
-        mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]);
-        mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
+        msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
+        msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
     }
-
-    // Cache essential information about the motion event to ensure that a malicious consumer
-    // cannot confuse the publisher by modifying the contents of the shared memory buffer while
-    // it is being updated.
-    if (action == AMOTION_EVENT_ACTION_MOVE
-            || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-        mMotionEventPointerCount = pointerCount;
-        mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
-        mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
-                mSharedMessage->motion.sampleData, mMotionEventSampleDataStride);
-    } else {
-        mMotionEventSampleDataTail = NULL;
-    }
-    return OK;
+    return mChannel->sendMessage(&msg);
 }
 
-status_t InputPublisher::appendMotionSample(
-        nsecs_t eventTime,
-        const PointerCoords* pointerCoords) {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' publisher ~ appendMotionSample: eventTime=%lld",
-            mChannel->getName().string(), eventTime);
-#endif
-
-    if (! mPinned || ! mMotionEventSampleDataTail) {
-        ALOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
-                "AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.",
-                mChannel->getName().string());
-        return INVALID_OPERATION;
-    }
-
-    InputMessage::SampleData* newTail = InputMessage::sampleDataPtrIncrement(
-            mMotionEventSampleDataTail, mMotionEventSampleDataStride);
-    size_t newBytesUsed = reinterpret_cast<char*>(newTail) -
-            reinterpret_cast<char*>(mSharedMessage);
-
-    if (newBytesUsed > mAshmemSize) {
-#if DEBUG_TRANSPORT_ACTIONS
-        ALOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory "
-                "buffer is full.  Buffer size: %d bytes, pointers: %d, samples: %d",
-                mChannel->getName().string(),
-                mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount);
-#endif
-        return NO_MEMORY;
-    }
-
-    int result;
-    if (mWasDispatched) {
-        result = sem_trywait(& mSharedMessage->semaphore);
-        if (result < 0) {
-            if (errno == EAGAIN) {
-                // Only possible source of contention is the consumer having consumed (or being in the
-                // process of consuming) the message and left the semaphore count at 0.
-#if DEBUG_TRANSPORT_ACTIONS
-                ALOGD("channel '%s' publisher ~ Cannot append motion sample because the message has "
-                        "already been consumed.", mChannel->getName().string());
-#endif
-                return FAILED_TRANSACTION;
-            } else {
-                ALOGE("channel '%s' publisher ~ Error %d in sem_trywait.",
-                        mChannel->getName().string(), errno);
-                return UNKNOWN_ERROR;
-            }
-        }
-    }
-
-    mMotionEventSampleDataTail->eventTime = eventTime;
-    for (size_t i = 0; i < mMotionEventPointerCount; i++) {
-        mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]);
-    }
-    mMotionEventSampleDataTail = newTail;
-
-    mSharedMessage->motion.sampleCount += 1;
-
-    if (mWasDispatched) {
-        result = sem_post(& mSharedMessage->semaphore);
-        if (result < 0) {
-            ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
-                    mChannel->getName().string(), errno);
-            return UNKNOWN_ERROR;
-        }
-    }
-    return OK;
-}
-
-status_t InputPublisher::sendDispatchSignal() {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' publisher ~ sendDispatchSignal",
-            mChannel->getName().string());
-#endif
-
-    mWasDispatched = true;
-    return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
-}
-
-status_t InputPublisher::receiveFinishedSignal(bool* outHandled) {
+status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
             mChannel->getName().string());
 #endif
 
-    char signal;
-    status_t result = mChannel->receiveSignal(& signal);
+    InputMessage msg;
+    status_t result = mChannel->receiveMessage(&msg);
     if (result) {
+        *outSeq = 0;
         *outHandled = false;
         return result;
     }
-    if (signal == INPUT_SIGNAL_FINISHED_HANDLED) {
-        *outHandled = true;
-    } else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) {
-        *outHandled = false;
-    } else {
-        ALOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
-                mChannel->getName().string(), signal);
+    if (msg.header.type != InputMessage::TYPE_FINISHED) {
+        ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
+                mChannel->getName().string(), msg.header.type);
         return UNKNOWN_ERROR;
     }
+    *outSeq = msg.body.finished.seq;
+    *outHandled = msg.body.finished.handled;
     return OK;
 }
 
 // --- InputConsumer ---
 
 InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
-        mChannel(channel), mSharedMessage(NULL) {
+        mChannel(channel), mMsgDeferred(false) {
 }
 
 InputConsumer::~InputConsumer() {
-    if (mSharedMessage) {
-        munmap(mSharedMessage, mAshmemSize);
-    }
 }
 
-status_t InputConsumer::initialize() {
+status_t InputConsumer::consume(InputEventFactoryInterface* factory,
+        bool consumeBatches, uint32_t* outSeq, InputEvent** outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' consumer ~ initialize",
-            mChannel->getName().string());
+    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s",
+            mChannel->getName().string(), consumeBatches ? "true" : "false");
 #endif
 
-    int ashmemFd = mChannel->getAshmemFd();
-    int result = ashmem_get_size_region(ashmemFd);
-    if (result < 0) {
-        ALOGE("channel '%s' consumer ~ Error %d getting size of ashmem fd %d.",
-                mChannel->getName().string(), result, ashmemFd);
-        return UNKNOWN_ERROR;
-    }
-
-    mAshmemSize = (size_t) result;
-
-    mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
-            PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
-    if (! mSharedMessage) {
-        ALOGE("channel '%s' consumer ~ mmap failed on ashmem fd %d.",
-                mChannel->getName().string(), ashmemFd);
-        return NO_MEMORY;
-    }
-
-    return OK;
-}
-
-status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
-#if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' consumer ~ consume",
-            mChannel->getName().string());
-#endif
-
+    *outSeq = 0;
     *outEvent = NULL;
 
-    int ashmemFd = mChannel->getAshmemFd();
-    int result = ashmem_pin_region(ashmemFd, 0, 0);
-    if (result != ASHMEM_NOT_PURGED) {
-        if (result == ASHMEM_WAS_PURGED) {
-            ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "
-                    "which probably indicates that the publisher and consumer are out of sync.",
-                    mChannel->getName().string(), result, ashmemFd);
-            return INVALID_OPERATION;
+    // Fetch the next input message.
+    // Loop until an event can be returned or no additional events are received.
+    while (!*outEvent) {
+        if (mMsgDeferred) {
+            // mMsg contains a valid input message from the previous call to consume
+            // that has not yet been processed.
+            mMsgDeferred = false;
+        } else {
+            // Receive a fresh message.
+            status_t result = mChannel->receiveMessage(&mMsg);
+            if (result) {
+                // Consume the next batched event unless batches are being held for later.
+                if (!mBatches.isEmpty() && (consumeBatches || result != WOULD_BLOCK)) {
+                    MotionEvent* motionEvent = factory->createMotionEvent();
+                    if (! motionEvent) return NO_MEMORY;
+
+                    const Batch& batch = mBatches.top();
+                    motionEvent->copyFrom(&batch.event, true /*keepHistory*/);
+                    *outSeq = batch.seq;
+                    *outEvent = motionEvent;
+                    mBatches.pop();
+#if DEBUG_TRANSPORT_ACTIONS
+                    ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
+                            mChannel->getName().string(), *outSeq);
+#endif
+                    break;
+                }
+                return result;
+            }
         }
 
-        ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
-                mChannel->getName().string(), result, ashmemFd);
-        return UNKNOWN_ERROR;
-    }
+        switch (mMsg.header.type) {
+        case InputMessage::TYPE_KEY: {
+            KeyEvent* keyEvent = factory->createKeyEvent();
+            if (!keyEvent) return NO_MEMORY;
 
-    if (mSharedMessage->consumed) {
-        ALOGE("channel '%s' consumer ~ The current message has already been consumed.",
-                mChannel->getName().string());
-        return INVALID_OPERATION;
-    }
-
-    // Acquire but *never release* the semaphore.  Contention on the semaphore is used to signal
-    // to the publisher that the message has been consumed (or is in the process of being
-    // consumed).  Eventually the publisher will reinitialize the semaphore for the next message.
-    result = sem_wait(& mSharedMessage->semaphore);
-    if (result < 0) {
-        ALOGE("channel '%s' consumer ~ Error %d in sem_wait.",
-                mChannel->getName().string(), errno);
-        return UNKNOWN_ERROR;
-    }
-
-    mSharedMessage->consumed = true;
-
-    switch (mSharedMessage->type) {
-    case AINPUT_EVENT_TYPE_KEY: {
-        KeyEvent* keyEvent = factory->createKeyEvent();
-        if (! keyEvent) return NO_MEMORY;
-
-        populateKeyEvent(keyEvent);
-
-        *outEvent = keyEvent;
-        break;
-    }
-
-    case AINPUT_EVENT_TYPE_MOTION: {
-        MotionEvent* motionEvent = factory->createMotionEvent();
-        if (! motionEvent) return NO_MEMORY;
-
-        populateMotionEvent(motionEvent);
-
-        *outEvent = motionEvent;
-        break;
-    }
-
-    default:
-        ALOGE("channel '%s' consumer ~ Received message of unknown type %d",
-                mChannel->getName().string(), mSharedMessage->type);
-        return UNKNOWN_ERROR;
-    }
-
-    return OK;
-}
-
-status_t InputConsumer::sendFinishedSignal(bool handled) {
+            initializeKeyEvent(keyEvent, &mMsg);
+            *outSeq = mMsg.body.key.seq;
+            *outEvent = keyEvent;
 #if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d",
-            mChannel->getName().string(), handled);
+            ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
+                    mChannel->getName().string(), *outSeq);
 #endif
+            break;
+        }
 
-    return mChannel->sendSignal(handled
-            ? INPUT_SIGNAL_FINISHED_HANDLED
-            : INPUT_SIGNAL_FINISHED_UNHANDLED);
-}
+        case AINPUT_EVENT_TYPE_MOTION: {
+            ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
+            if (batchIndex >= 0) {
+                Batch& batch = mBatches.editItemAt(batchIndex);
+                if (canAppendSamples(&batch.event, &mMsg)) {
+                    // Append to the batch and save the new sequence number for the tail end.
+                    uint32_t chain = batch.seq;
+                    appendSamples(&batch.event, &mMsg);
+                    batch.seq = mMsg.body.motion.seq;
 
-status_t InputConsumer::receiveDispatchSignal() {
+                    // Update the sequence number chain.
+                    SeqChain seqChain;
+                    seqChain.seq = batch.seq;
+                    seqChain.chain = chain;
+                    mSeqChains.push(seqChain);
 #if DEBUG_TRANSPORT_ACTIONS
-    ALOGD("channel '%s' consumer ~ receiveDispatchSignal",
-            mChannel->getName().string());
+                    ALOGD("channel '%s' consumer ~ appended to batch event",
+                            mChannel->getName().string());
 #endif
+                    break;
+                } else {
+                    MotionEvent* motionEvent = factory->createMotionEvent();
+                    if (! motionEvent) return NO_MEMORY;
 
-    char signal;
-    status_t result = mChannel->receiveSignal(& signal);
-    if (result) {
-        return result;
-    }
-    if (signal != INPUT_SIGNAL_DISPATCH) {
-        ALOGE("channel '%s' consumer ~ Received unexpected signal '%c' from publisher",
-                mChannel->getName().string(), signal);
-        return UNKNOWN_ERROR;
+                    // We cannot append to the batch in progress, so we need to consume
+                    // the previous batch right now and defer the new message until later.
+                    mMsgDeferred = true;
+
+                    // Return the end of the previous batch.
+                    motionEvent->copyFrom(&batch.event, true /*keepHistory*/);
+                    *outSeq = batch.seq;
+                    *outEvent = motionEvent;
+                    mBatches.removeAt(batchIndex);
+#if DEBUG_TRANSPORT_ACTIONS
+                    ALOGD("channel '%s' consumer ~ consumed batch event and "
+                            "deferred current event, seq=%u",
+                            mChannel->getName().string(), *outSeq);
+#endif
+                    break;
+                }
+            }
+
+            // Start a new batch if needed.
+            if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
+                    || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+                mBatches.push();
+                Batch& batch = mBatches.editTop();
+                batch.seq = mMsg.body.motion.seq;
+                initializeMotionEvent(&batch.event, &mMsg);
+#if DEBUG_TRANSPORT_ACTIONS
+                ALOGD("channel '%s' consumer ~ started batch event",
+                        mChannel->getName().string());
+#endif
+                break;
+            }
+
+            MotionEvent* motionEvent = factory->createMotionEvent();
+            if (! motionEvent) return NO_MEMORY;
+
+            initializeMotionEvent(motionEvent, &mMsg);
+            *outSeq = mMsg.body.motion.seq;
+            *outEvent = motionEvent;
+#if DEBUG_TRANSPORT_ACTIONS
+            ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
+                    mChannel->getName().string(), *outSeq);
+#endif
+            break;
+        }
+
+        default:
+            ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
+                    mChannel->getName().string(), mMsg.header.type);
+            return UNKNOWN_ERROR;
+        }
     }
     return OK;
 }
 
-void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const {
-    keyEvent->initialize(
-            mSharedMessage->deviceId,
-            mSharedMessage->source,
-            mSharedMessage->key.action,
-            mSharedMessage->key.flags,
-            mSharedMessage->key.keyCode,
-            mSharedMessage->key.scanCode,
-            mSharedMessage->key.metaState,
-            mSharedMessage->key.repeatCount,
-            mSharedMessage->key.downTime,
-            mSharedMessage->key.eventTime);
-}
+status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
+#if DEBUG_TRANSPORT_ACTIONS
+    ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
+            mChannel->getName().string(), seq, handled ? "true" : "false");
+#endif
 
-void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
-    motionEvent->initialize(
-            mSharedMessage->deviceId,
-            mSharedMessage->source,
-            mSharedMessage->motion.action,
-            mSharedMessage->motion.flags,
-            mSharedMessage->motion.edgeFlags,
-            mSharedMessage->motion.metaState,
-            mSharedMessage->motion.buttonState,
-            mSharedMessage->motion.xOffset,
-            mSharedMessage->motion.yOffset,
-            mSharedMessage->motion.xPrecision,
-            mSharedMessage->motion.yPrecision,
-            mSharedMessage->motion.downTime,
-            mSharedMessage->motion.sampleData[0].eventTime,
-            mSharedMessage->motion.pointerCount,
-            mSharedMessage->motion.pointerProperties,
-            mSharedMessage->motion.sampleData[0].coords);
+    if (!seq) {
+        ALOGE("Attempted to send a finished signal with sequence number 0.");
+        return BAD_VALUE;
+    }
 
-    size_t sampleCount = mSharedMessage->motion.sampleCount;
-    if (sampleCount > 1) {
-        InputMessage::SampleData* sampleData = mSharedMessage->motion.sampleData;
-        size_t sampleDataStride = InputMessage::sampleDataStride(
-                mSharedMessage->motion.pointerCount);
-
-        while (--sampleCount > 0) {
-            sampleData = InputMessage::sampleDataPtrIncrement(sampleData, sampleDataStride);
-            motionEvent->addSample(sampleData->eventTime, sampleData->coords);
+    // Send finished signals for the batch sequence chain first.
+    size_t seqChainCount = mSeqChains.size();
+    if (seqChainCount) {
+        uint32_t currentSeq = seq;
+        uint32_t chainSeqs[seqChainCount];
+        size_t chainIndex = 0;
+        for (size_t i = seqChainCount; i-- > 0; ) {
+             const SeqChain& seqChain = mSeqChains.itemAt(i);
+             if (seqChain.seq == currentSeq) {
+                 currentSeq = seqChain.chain;
+                 chainSeqs[chainIndex++] = currentSeq;
+                 mSeqChains.removeAt(i);
+             }
+        }
+        status_t status = OK;
+        while (!status && chainIndex-- > 0) {
+            status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
+        }
+        if (status) {
+            // An error occurred so at least one signal was not sent, reconstruct the chain.
+            do {
+                SeqChain seqChain;
+                seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
+                seqChain.chain = chainSeqs[chainIndex];
+                mSeqChains.push(seqChain);
+            } while (chainIndex-- > 0);
+            return status;
         }
     }
+
+    // Send finished signal for the last message in the batch.
+    return sendUnchainedFinishedSignal(seq, handled);
+}
+
+status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
+    InputMessage msg;
+    msg.header.type = InputMessage::TYPE_FINISHED;
+    msg.body.finished.seq = seq;
+    msg.body.finished.handled = handled;
+    return mChannel->sendMessage(&msg);
+}
+
+bool InputConsumer::hasPendingBatch() const {
+    return !mBatches.isEmpty();
+}
+
+ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
+    for (size_t i = 0; i < mBatches.size(); i++) {
+        const Batch& batch = mBatches.itemAt(i);
+        if (batch.event.getDeviceId() == deviceId && batch.event.getSource() == source) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
+    event->initialize(
+            msg->body.key.deviceId,
+            msg->body.key.source,
+            msg->body.key.action,
+            msg->body.key.flags,
+            msg->body.key.keyCode,
+            msg->body.key.scanCode,
+            msg->body.key.metaState,
+            msg->body.key.repeatCount,
+            msg->body.key.downTime,
+            msg->body.key.eventTime);
+}
+
+void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
+    size_t pointerCount = msg->body.motion.pointerCount;
+    PointerProperties pointerProperties[pointerCount];
+    PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
+        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
+    }
+
+    event->initialize(
+            msg->body.motion.deviceId,
+            msg->body.motion.source,
+            msg->body.motion.action,
+            msg->body.motion.flags,
+            msg->body.motion.edgeFlags,
+            msg->body.motion.metaState,
+            msg->body.motion.buttonState,
+            msg->body.motion.xOffset,
+            msg->body.motion.yOffset,
+            msg->body.motion.xPrecision,
+            msg->body.motion.yPrecision,
+            msg->body.motion.downTime,
+            msg->body.motion.eventTime,
+            pointerCount,
+            pointerProperties,
+            pointerCoords);
+}
+
+bool InputConsumer::canAppendSamples(const MotionEvent* event, const InputMessage *msg) {
+    size_t pointerCount = msg->body.motion.pointerCount;
+    if (event->getPointerCount() != pointerCount
+            || event->getAction() != msg->body.motion.action) {
+        return false;
+    }
+    for (size_t i = 0; i < pointerCount; i++) {
+        if (*event->getPointerProperties(i) != msg->body.motion.pointers[i].properties) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void InputConsumer::appendSamples(MotionEvent* event, const InputMessage* msg) {
+    size_t pointerCount = msg->body.motion.pointerCount;
+    PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
+    }
+
+    event->setMetaState(event->getMetaState() | msg->body.motion.metaState);
+    event->addSample(msg->body.motion.eventTime, pointerCoords);
 }
 
 } // namespace android
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 8cd047a..6e2e731 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -126,6 +126,9 @@
 Region& Region::orSelf(const Rect& r) {
     return operationSelf(r, op_or);
 }
+Region& Region::xorSelf(const Rect& r) {
+    return operationSelf(r, op_xor);
+}
 Region& Region::andSelf(const Rect& r) {
     return operationSelf(r, op_and);
 }
@@ -143,6 +146,9 @@
 Region& Region::orSelf(const Region& rhs) {
     return operationSelf(rhs, op_or);
 }
+Region& Region::xorSelf(const Region& rhs) {
+    return operationSelf(rhs, op_xor);
+}
 Region& Region::andSelf(const Region& rhs) {
     return operationSelf(rhs, op_and);
 }
@@ -165,6 +171,9 @@
 const Region Region::merge(const Rect& rhs) const {
     return operation(rhs, op_or);
 }
+const Region Region::mergeExclusive(const Rect& rhs) const {
+    return operation(rhs, op_xor);
+}
 const Region Region::intersect(const Rect& rhs) const {
     return operation(rhs, op_and);
 }
@@ -182,6 +191,9 @@
 const Region Region::merge(const Region& rhs) const {
     return operation(rhs, op_or);
 }
+const Region Region::mergeExclusive(const Region& rhs) const {
+    return operation(rhs, op_xor);
+}
 const Region Region::intersect(const Region& rhs) const {
     return operation(rhs, op_and);
 }
@@ -205,6 +217,9 @@
 Region& Region::orSelf(const Region& rhs, int dx, int dy) {
     return operationSelf(rhs, dx, dy, op_or);
 }
+Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
+    return operationSelf(rhs, dx, dy, op_xor);
+}
 Region& Region::andSelf(const Region& rhs, int dx, int dy) {
     return operationSelf(rhs, dx, dy, op_and);
 }
@@ -222,6 +237,9 @@
 const Region Region::merge(const Region& rhs, int dx, int dy) const {
     return operation(rhs, dx, dy, op_or);
 }
+const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
+    return operation(rhs, dx, dy, op_xor);
+}
 const Region Region::intersect(const Region& rhs, int dx, int dy) const {
     return operation(rhs, dx, dy, op_and);
 }
@@ -421,6 +439,7 @@
     SkRegion::Op sk_op;
     switch (op) {
         case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
+        case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
         case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
         case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
     }
diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/ui/tests/InputChannel_test.cpp
index eff22ee..ee422fe 100644
--- a/libs/ui/tests/InputChannel_test.cpp
+++ b/libs/ui/tests/InputChannel_test.cpp
@@ -20,8 +20,7 @@
 #include <gtest/gtest.h>
 #include <unistd.h>
 #include <time.h>
-#include <sys/mman.h>
-#include <cutils/ashmem.h>
+#include <errno.h>
 
 #include "../../utils/tests/TestHelpers.h"
 
@@ -36,35 +35,24 @@
 
 TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) {
     // Our purpose here is to verify that the input channel destructor closes the
-    // file descriptors provided to it.  One easy way is to provide it with one end
+    // file descriptor provided to it.  One easy way is to provide it with one end
     // of a pipe and to check for EPIPE on the other end after the channel is destroyed.
-    Pipe fakeAshmem, sendPipe, receivePipe;
+    Pipe pipe;
 
-    sp<InputChannel> inputChannel = new InputChannel(String8("channel name"),
-            fakeAshmem.sendFd, receivePipe.receiveFd, sendPipe.sendFd);
+    sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd);
 
     EXPECT_STREQ("channel name", inputChannel->getName().string())
             << "channel should have provided name";
-    EXPECT_EQ(fakeAshmem.sendFd, inputChannel->getAshmemFd())
-            << "channel should have provided ashmem fd";
-    EXPECT_EQ(receivePipe.receiveFd, inputChannel->getReceivePipeFd())
-            << "channel should have provided receive pipe fd";
-    EXPECT_EQ(sendPipe.sendFd, inputChannel->getSendPipeFd())
-            << "channel should have provided send pipe fd";
+    EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
+            << "channel should have provided fd";
 
     inputChannel.clear(); // destroys input channel
 
-    EXPECT_EQ(-EPIPE, fakeAshmem.readSignal())
-            << "channel should have closed ashmem fd when destroyed";
-    EXPECT_EQ(-EPIPE, receivePipe.writeSignal())
-            << "channel should have closed receive pipe fd when destroyed";
-    EXPECT_EQ(-EPIPE, sendPipe.readSignal())
-            << "channel should have closed send pipe fd when destroyed";
+    EXPECT_EQ(-EPIPE, pipe.readSignal())
+            << "channel should have closed fd when destroyed";
 
     // clean up fds of Pipe endpoints that were closed so we don't try to close them again
-    fakeAshmem.sendFd = -1;
-    receivePipe.receiveFd = -1;
-    sendPipe.sendFd = -1;
+    pipe.sendFd = -1;
 }
 
 TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
@@ -82,43 +70,40 @@
     EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
             << "client channel should have suffixed name";
 
-    // Ashmem uniqueness
-    EXPECT_NE(serverChannel->getAshmemFd(), clientChannel->getAshmemFd())
-            << "server and client channel should have different ashmem fds because it was dup'd";
-
-    // Ashmem usability
-    ssize_t serverAshmemSize = ashmem_get_size_region(serverChannel->getAshmemFd());
-    ssize_t clientAshmemSize = ashmem_get_size_region(clientChannel->getAshmemFd());
-    uint32_t* serverAshmem = static_cast<uint32_t*>(mmap(NULL, serverAshmemSize,
-            PROT_READ | PROT_WRITE, MAP_SHARED, serverChannel->getAshmemFd(), 0));
-    uint32_t* clientAshmem = static_cast<uint32_t*>(mmap(NULL, clientAshmemSize,
-            PROT_READ | PROT_WRITE, MAP_SHARED, clientChannel->getAshmemFd(), 0));
-    ASSERT_TRUE(serverAshmem != NULL)
-            << "server channel ashmem should be mappable";
-    ASSERT_TRUE(clientAshmem != NULL)
-            << "client channel ashmem should be mappable";
-    *serverAshmem = 0xf00dd00d;
-    EXPECT_EQ(0xf00dd00d, *clientAshmem)
-            << "ashmem buffer should be shared by client and server";
-    munmap(serverAshmem, serverAshmemSize);
-    munmap(clientAshmem, clientAshmemSize);
-
     // Server->Client communication
-    EXPECT_EQ(OK, serverChannel->sendSignal('S'))
-            << "server channel should be able to send signal to client channel";
-    char signal;
-    EXPECT_EQ(OK, clientChannel->receiveSignal(& signal))
-            << "client channel should be able to receive signal from server channel";
-    EXPECT_EQ('S', signal)
-            << "client channel should receive the correct signal from server channel";
+    InputMessage serverMsg;
+    memset(&serverMsg, 0, sizeof(InputMessage));
+    serverMsg.header.type = InputMessage::TYPE_KEY;
+    serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
+    EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
+            << "server channel should be able to send message to client channel";
+
+    InputMessage clientMsg;
+    EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
+            << "client channel should be able to receive message from server channel";
+    EXPECT_EQ(serverMsg.header.type, clientMsg.header.type)
+            << "client channel should receive the correct message from server channel";
+    EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action)
+            << "client channel should receive the correct message from server channel";
 
     // Client->Server communication
-    EXPECT_EQ(OK, clientChannel->sendSignal('c'))
-            << "client channel should be able to send signal to server channel";
-    EXPECT_EQ(OK, serverChannel->receiveSignal(& signal))
-            << "server channel should be able to receive signal from client channel";
-    EXPECT_EQ('c', signal)
-            << "server channel should receive the correct signal from client channel";
+    InputMessage clientReply;
+    memset(&clientReply, 0, sizeof(InputMessage));
+    clientReply.header.type = InputMessage::TYPE_FINISHED;
+    clientReply.body.finished.seq = 0x11223344;
+    clientReply.body.finished.handled = true;
+    EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply))
+            << "client channel should be able to send message to server channel";
+
+    InputMessage serverReply;
+    EXPECT_EQ(OK, serverChannel->receiveMessage(&serverReply))
+            << "server channel should be able to receive message from client channel";
+    EXPECT_EQ(clientReply.header.type, serverReply.header.type)
+            << "server channel should receive the correct message from client channel";
+    EXPECT_EQ(clientReply.body.finished.seq, serverReply.body.finished.seq)
+            << "server channel should receive the correct message from client channel";
+    EXPECT_EQ(clientReply.body.finished.handled, serverReply.body.finished.handled)
+            << "server channel should receive the correct message from client channel";
 }
 
 TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
@@ -130,9 +115,9 @@
     ASSERT_EQ(OK, result)
             << "should have successfully opened a channel pair";
 
-    char signal;
-    EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveSignal(& signal))
-            << "receiveSignal should have returned WOULD_BLOCK";
+    InputMessage msg;
+    EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveMessage(&msg))
+            << "receiveMessage should have returned WOULD_BLOCK";
 }
 
 TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
@@ -146,9 +131,9 @@
 
     serverChannel.clear(); // close server channel
 
-    char signal;
-    EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveSignal(& signal))
-            << "receiveSignal should have returned DEAD_OBJECT";
+    InputMessage msg;
+    EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg))
+            << "receiveMessage should have returned DEAD_OBJECT";
 }
 
 TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
@@ -162,8 +147,10 @@
 
     serverChannel.clear(); // close server channel
 
-    EXPECT_EQ(DEAD_OBJECT, clientChannel->sendSignal('S'))
-            << "sendSignal should have returned DEAD_OBJECT";
+    InputMessage msg;
+    msg.header.type = InputMessage::TYPE_KEY;
+    EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg))
+            << "sendMessage should have returned DEAD_OBJECT";
 }
 
 
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index fcc4cad..3303053 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -57,11 +57,8 @@
         clientChannel.clear();
     }
 
-    void Initialize();
     void PublishAndConsumeKeyEvent();
-    void PublishAndConsumeMotionEvent(
-            size_t samplesToAppendBeforeDispatch = 0,
-            size_t samplesToAppendAfterDispatch = 0);
+    void PublishAndConsumeMotionEvent();
 };
 
 TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
@@ -69,21 +66,10 @@
     EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get());
 }
 
-void InputPublisherAndConsumerTest::Initialize() {
-    status_t status;
-
-    status = mPublisher->initialize();
-    ASSERT_EQ(OK, status)
-            << "publisher initialize should return OK";
-
-    status = mConsumer->initialize();
-    ASSERT_EQ(OK, status)
-            << "consumer initialize should return OK";
-}
-
 void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
     status_t status;
 
+    const uint32_t seq = 15;
     const int32_t deviceId = 1;
     const int32_t source = AINPUT_SOURCE_KEYBOARD;
     const int32_t action = AKEY_EVENT_ACTION_DOWN;
@@ -95,21 +81,14 @@
     const nsecs_t downTime = 3;
     const nsecs_t eventTime = 4;
 
-    status = mPublisher->publishKeyEvent(deviceId, source, action, flags,
+    status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags,
             keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
     ASSERT_EQ(OK, status)
             << "publisher publishKeyEvent should return OK";
 
-    status = mPublisher->sendDispatchSignal();
-    ASSERT_EQ(OK, status)
-            << "publisher sendDispatchSignal should return OK";
-
-    status = mConsumer->receiveDispatchSignal();
-    ASSERT_EQ(OK, status)
-            << "consumer receiveDispatchSignal should return OK";
-
+    uint32_t consumeSeq;
     InputEvent* event;
-    status = mConsumer->consume(& mEventFactory, & event);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, &consumeSeq, &event);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
@@ -119,6 +98,7 @@
             << "consumer should have returned a key event";
 
     KeyEvent* keyEvent = static_cast<KeyEvent*>(event);
+    EXPECT_EQ(seq, consumeSeq);
     EXPECT_EQ(deviceId, keyEvent->getDeviceId());
     EXPECT_EQ(source, keyEvent->getSource());
     EXPECT_EQ(action, keyEvent->getAction());
@@ -130,26 +110,25 @@
     EXPECT_EQ(downTime, keyEvent->getDownTime());
     EXPECT_EQ(eventTime, keyEvent->getEventTime());
 
-    status = mConsumer->sendFinishedSignal(true);
+    status = mConsumer->sendFinishedSignal(seq, true);
     ASSERT_EQ(OK, status)
             << "consumer sendFinishedSignal should return OK";
 
+    uint32_t finishedSeq = 0;
     bool handled = false;
-    status = mPublisher->receiveFinishedSignal(&handled);
+    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
     ASSERT_EQ(OK, status)
             << "publisher receiveFinishedSignal should return OK";
+    ASSERT_EQ(seq, finishedSeq)
+            << "publisher receiveFinishedSignal should have returned the original sequence number";
     ASSERT_TRUE(handled)
             << "publisher receiveFinishedSignal should have set handled to consumer's reply";
-
-    status = mPublisher->reset();
-    ASSERT_EQ(OK, status)
-            << "publisher reset should return OK";
 }
 
-void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
-        size_t samplesToAppendBeforeDispatch, size_t samplesToAppendAfterDispatch) {
+void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
     status_t status;
 
+    const uint32_t seq = 15;
     const int32_t deviceId = 1;
     const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
     const int32_t action = AMOTION_EVENT_ACTION_MOVE;
@@ -163,67 +142,36 @@
     const float yPrecision = 0.5;
     const nsecs_t downTime = 3;
     const size_t pointerCount = 3;
+    const nsecs_t eventTime = 4;
     PointerProperties pointerProperties[pointerCount];
+    PointerCoords pointerCoords[pointerCount];
     for (size_t i = 0; i < pointerCount; i++) {
         pointerProperties[i].clear();
         pointerProperties[i].id = (i + 2) % pointerCount;
         pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+        pointerCoords[i].clear();
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
     }
 
-    Vector<nsecs_t> sampleEventTimes;
-    Vector<PointerCoords> samplePointerCoords;
-
-    for (size_t i = 0; i <= samplesToAppendAfterDispatch + samplesToAppendBeforeDispatch; i++) {
-        sampleEventTimes.push(i + 10);
-        for (size_t j = 0; j < pointerCount; j++) {
-            samplePointerCoords.push();
-            PointerCoords& pc = samplePointerCoords.editTop();
-            pc.clear();
-            pc.setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i + j);
-            pc.setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i + j);
-            pc.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i + j);
-            pc.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i + j);
-            pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i + j);
-            pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i + j);
-            pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i + j);
-            pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i + j);
-            pc.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i + j);
-        }
-    }
-
-    status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags,
+    status = mPublisher->publishMotionEvent(seq, deviceId, source, action, flags, edgeFlags,
             metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
-            downTime, sampleEventTimes[0], pointerCount,
-            pointerProperties, samplePointerCoords.array());
+            downTime, eventTime, pointerCount,
+            pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
-    for (size_t i = 0; i < samplesToAppendBeforeDispatch; i++) {
-        size_t sampleIndex = i + 1;
-        status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
-                samplePointerCoords.array() + sampleIndex * pointerCount);
-        ASSERT_EQ(OK, status)
-                << "publisher appendMotionEvent should return OK";
-    }
-
-    status = mPublisher->sendDispatchSignal();
-    ASSERT_EQ(OK, status)
-            << "publisher sendDispatchSignal should return OK";
-
-    for (size_t i = 0; i < samplesToAppendAfterDispatch; i++) {
-        size_t sampleIndex = i + 1 + samplesToAppendBeforeDispatch;
-        status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
-                samplePointerCoords.array() + sampleIndex * pointerCount);
-        ASSERT_EQ(OK, status)
-                << "publisher appendMotionEvent should return OK";
-    }
-
-    status = mConsumer->receiveDispatchSignal();
-    ASSERT_EQ(OK, status)
-            << "consumer receiveDispatchSignal should return OK";
-
+    uint32_t consumeSeq;
     InputEvent* event;
-    status = mConsumer->consume(& mEventFactory, & event);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, &consumeSeq, &event);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
@@ -232,9 +180,8 @@
     ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
             << "consumer should have returned a motion event";
 
-    size_t lastSampleIndex = samplesToAppendBeforeDispatch + samplesToAppendAfterDispatch;
-
     MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
+    EXPECT_EQ(seq, consumeSeq);
     EXPECT_EQ(deviceId, motionEvent->getDeviceId());
     EXPECT_EQ(source, motionEvent->getSource());
     EXPECT_EQ(action, motionEvent->getAction());
@@ -245,150 +192,69 @@
     EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
     EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
     EXPECT_EQ(downTime, motionEvent->getDownTime());
-    EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
+    EXPECT_EQ(eventTime, motionEvent->getEventTime());
     EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
-    EXPECT_EQ(lastSampleIndex, motionEvent->getHistorySize());
+    EXPECT_EQ(0U, motionEvent->getHistorySize());
 
     for (size_t i = 0; i < pointerCount; i++) {
         SCOPED_TRACE(i);
         EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
         EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
-    }
 
-    for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) {
-        SCOPED_TRACE(sampleIndex);
-        EXPECT_EQ(sampleEventTimes[sampleIndex],
-                motionEvent->getHistoricalEventTime(sampleIndex));
-        for (size_t i = 0; i < pointerCount; i++) {
-            SCOPED_TRACE(i);
-            size_t offset = sampleIndex * pointerCount + i;
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
-                    motionEvent->getHistoricalRawX(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
-                    motionEvent->getHistoricalRawY(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
-                    motionEvent->getHistoricalX(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
-                    motionEvent->getHistoricalY(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
-                    motionEvent->getHistoricalPressure(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
-                    motionEvent->getHistoricalSize(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
-                    motionEvent->getHistoricalTouchMajor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
-                    motionEvent->getHistoricalTouchMinor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
-                    motionEvent->getHistoricalToolMajor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
-                    motionEvent->getHistoricalToolMinor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
-                    motionEvent->getHistoricalOrientation(i, sampleIndex));
-        }
-    }
-
-    SCOPED_TRACE(lastSampleIndex);
-    EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
-    for (size_t i = 0; i < pointerCount; i++) {
-        SCOPED_TRACE(i);
-        size_t offset = lastSampleIndex * pointerCount + i;
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
                 motionEvent->getRawX(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
                 motionEvent->getRawY(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
                 motionEvent->getX(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
                 motionEvent->getY(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
                 motionEvent->getPressure(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
                 motionEvent->getSize(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
                 motionEvent->getTouchMajor(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
                 motionEvent->getTouchMinor(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
                 motionEvent->getToolMajor(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
                 motionEvent->getToolMinor(i));
-        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
+        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
                 motionEvent->getOrientation(i));
     }
 
-    status = mConsumer->sendFinishedSignal(false);
+    status = mConsumer->sendFinishedSignal(seq, false);
     ASSERT_EQ(OK, status)
             << "consumer sendFinishedSignal should return OK";
 
+    uint32_t finishedSeq = 0;
     bool handled = true;
-    status = mPublisher->receiveFinishedSignal(&handled);
+    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
     ASSERT_EQ(OK, status)
             << "publisher receiveFinishedSignal should return OK";
+    ASSERT_EQ(seq, finishedSeq)
+            << "publisher receiveFinishedSignal should have returned the original sequence number";
     ASSERT_FALSE(handled)
             << "publisher receiveFinishedSignal should have set handled to consumer's reply";
-
-    status = mPublisher->reset();
-    ASSERT_EQ(OK, status)
-            << "publisher reset should return OK";
 }
 
 TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
-    ASSERT_NO_FATAL_FAILURE(Initialize());
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
 }
 
-TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_WhenNotReset_ReturnsError) {
-    status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-
-    status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
-    ASSERT_EQ(OK, status)
-            << "publisher publishKeyEvent should return OK first time";
-
-    status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
-    ASSERT_EQ(INVALID_OPERATION, status)
-            << "publisher publishKeyEvent should return INVALID_OPERATION because "
-                    "the publisher was not reset";
-}
-
 TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) {
-    ASSERT_NO_FATAL_FAILURE(Initialize());
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
 }
 
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsError) {
-    status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-
-    const size_t pointerCount = 1;
-    PointerProperties pointerProperties[pointerCount];
-    PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].clear();
-        pointerCoords[i].clear();
-    }
-
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerProperties, pointerCoords);
-    ASSERT_EQ(OK, status)
-            << "publisher publishMotionEvent should return OK";
-
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerProperties, pointerCoords);
-    ASSERT_EQ(INVALID_OPERATION, status)
-            << "publisher publishMotionEvent should return INVALID_OPERATION because ";
-                    "the publisher was not reset";
-}
-
 TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
     status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-
     const size_t pointerCount = 0;
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
@@ -396,8 +262,6 @@
 
 TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
     status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-
     const size_t pointerCount = MAX_POINTERS + 1;
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
@@ -406,14 +270,13 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
 
 TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
-    ASSERT_NO_FATAL_FAILURE(Initialize());
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
@@ -421,111 +284,4 @@
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
 }
 
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledBeforeDispatchSignal_AppendsSamples) {
-    status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(3, 0));
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledAfterDispatchSignalAndNotConsumed_AppendsSamples) {
-    status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(0, 4));
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenNoMotionEventPublished_ReturnsError) {
-    status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-
-    PointerCoords pointerCoords[1];
-    status = mPublisher->appendMotionSample(0, pointerCoords);
-    ASSERT_EQ(INVALID_OPERATION, status)
-            << "publisher appendMotionSample should return INVALID_OPERATION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEventIsNotAMove_ReturnsError) {
-    status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-
-    const size_t pointerCount = MAX_POINTERS;
-    PointerProperties pointerProperties[pointerCount];
-    PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].clear();
-        pointerCoords[i].clear();
-    }
-
-    status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
-    ASSERT_EQ(OK, status);
-
-    status = mPublisher->appendMotionSample(0, pointerCoords);
-    ASSERT_EQ(INVALID_OPERATION, status)
-            << "publisher appendMotionSample should return INVALID_OPERATION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_ReturnsError) {
-    status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-
-    const size_t pointerCount = MAX_POINTERS;
-    PointerProperties pointerProperties[pointerCount];
-    PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].clear();
-        pointerCoords[i].clear();
-    }
-
-    status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
-    ASSERT_EQ(OK, status);
-
-    status = mPublisher->sendDispatchSignal();
-    ASSERT_EQ(OK, status);
-
-    status = mConsumer->receiveDispatchSignal();
-    ASSERT_EQ(OK, status);
-
-    InputEvent* event;
-    status = mConsumer->consume(& mEventFactory, & event);
-    ASSERT_EQ(OK, status);
-
-    status = mPublisher->appendMotionSample(0, pointerCoords);
-    ASSERT_EQ(status_t(FAILED_TRANSACTION), status)
-            << "publisher appendMotionSample should return FAILED_TRANSACTION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsError) {
-    status_t status;
-    ASSERT_NO_FATAL_FAILURE(Initialize());
-
-    const size_t pointerCount = MAX_POINTERS;
-    PointerProperties pointerProperties[pointerCount];
-    PointerCoords pointerCoords[pointerCount];
-    for (size_t i = 0; i < pointerCount; i++) {
-        pointerProperties[i].clear();
-        pointerCoords[i].clear();
-    }
-
-    status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
-    ASSERT_EQ(OK, status);
-
-    for (int count = 1;; count++) {
-        ASSERT_LT(count, 100000) << "should eventually reach OOM";
-
-        status = mPublisher->appendMotionSample(0, pointerCoords);
-        if (status != OK) {
-            ASSERT_GT(count, 12) << "should be able to add at least a dozen samples";
-            ASSERT_EQ(NO_MEMORY, status)
-                    << "publisher appendMotionSample should return NO_MEMORY when buffer is full";
-            break;
-        }
-    }
-
-    status = mPublisher->appendMotionSample(0, pointerCoords);
-    ASSERT_EQ(NO_MEMORY, status)
-            << "publisher appendMotionSample should return NO_MEMORY persistently until reset";
-}
-
 } // namespace android
diff --git a/libs/usb/tests/AccessoryChat/Android.mk b/libs/usb/tests/AccessoryChat/Android.mk
index 77b8424..ecb455a 100644
--- a/libs/usb/tests/AccessoryChat/Android.mk
+++ b/libs/usb/tests/AccessoryChat/Android.mk
@@ -23,9 +23,4 @@
 
 LOCAL_PACKAGE_NAME := AccessoryChat
 
-LOCAL_JAVA_LIBRARIES := com.android.future.usb.accessory
-
-# Force an old SDK version to make sure we aren't using newer UsbManager APIs
-LOCAL_SDK_VERSION := 8
-
 include $(BUILD_PACKAGE)
diff --git a/libs/usb/tests/AccessoryChat/AndroidManifest.xml b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
index 802b715..6667eba 100644
--- a/libs/usb/tests/AccessoryChat/AndroidManifest.xml
+++ b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
@@ -17,8 +17,9 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.accessorychat">
 
+    <uses-feature android:name="android.hardware.usb.accessory" />
+
     <application android:label="Accessory Chat">
-        <uses-library android:name="com.android.future.usb.accessory" />
 
         <activity android:name="AccessoryChat" android:label="Accessory Chat">
             <intent-filter>
@@ -35,5 +36,5 @@
                 android:resource="@xml/accessory_filter" />
         </activity>
     </application>
-    <uses-sdk android:minSdkVersion="10" />
+    <uses-sdk android:minSdkVersion="12" />
 </manifest>
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
index 85b52dd..06b477f 100644
--- a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
+++ b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
@@ -98,7 +98,7 @@
     vendorId = usb_device_get_vendor_id(device);
     productId = usb_device_get_product_id(device);
 
-    if (vendorId == 0x18D1 || vendorId == 0x22B8) {
+    if (vendorId == 0x18D1 || vendorId == 0x22B8 || vendorId == 0x04e8) {
         if (!sDevice && (productId == 0x2D00 || productId == 0x2D01)) {
             struct usb_descriptor_header* desc;
             struct usb_descriptor_iter iter;
diff --git a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
index c3f4fa3..bf0cef0 100644
--- a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
+++ b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
@@ -33,8 +33,8 @@
 import android.widget.EditText;
 import android.widget.TextView;
 
-import com.android.future.usb.UsbAccessory;
-import com.android.future.usb.UsbManager;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbAccessory;
 
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -64,9 +64,11 @@
         public void onReceive(Context context, Intent intent) {
             if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
                 synchronized (this) {
-                    UsbAccessory accessory = UsbManager.getAccessory(intent);
+                    UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
                     if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
-                        openAccessory(accessory);
+                        if (accessory != null) {
+                            openAccessory(accessory);
+                        }
                     } else {
                         Log.d(TAG, "permission denied for accessory " + accessory);
                     }
@@ -80,7 +82,7 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mUsbManager = UsbManager.getInstance(this);
+        mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
         mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
         IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
         registerReceiver(mUsbReceiver, filter);
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 544ab74..24cf504 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -98,7 +98,8 @@
 
 LOCAL_C_INCLUDES += \
 		external/zlib \
-		external/icu4c/common
+		external/icu4c/common \
+		bionic/libc/private
 
 LOCAL_LDLIBS += -lpthread
 
@@ -114,7 +115,10 @@
 
 ifeq ($(TARGET_OS),linux)
 include $(CLEAR_VARS)
-LOCAL_C_INCLUDES += external/zlib external/icu4c/common
+LOCAL_C_INCLUDES += \
+		external/zlib \
+		external/icu4c/common \
+		bionic/libc/private
 LOCAL_LDLIBS := -lrt -ldl -lpthread
 LOCAL_MODULE := libutils
 LOCAL_SRC_FILES := $(commonSources) BackupData.cpp BackupHelpers.cpp
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 15b83bb..3fa562e 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -221,7 +221,7 @@
 static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes)
 {
     if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) {
-        ALOGW("idmap assertion failed: size=%d bytes\n", sizeBytes);
+        ALOGW("idmap assertion failed: size=%d bytes\n", (int)sizeBytes);
         return false;
     }
     if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess
@@ -250,7 +250,7 @@
         return UNKNOWN_ERROR;
     }
     if (typeCount > size) {
-        ALOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, size);
+        ALOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, (int)size);
         return UNKNOWN_ERROR;
     }
     const uint32_t typeOffset = map[type];
@@ -260,7 +260,7 @@
     }
     if (typeOffset + 1 > size) {
         ALOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n",
-             typeOffset, size);
+             typeOffset, (int)size);
         return UNKNOWN_ERROR;
     }
     const uint32_t entryCount = map[typeOffset];
@@ -271,7 +271,7 @@
     }
     const uint32_t index = typeOffset + 2 + entry - entryOffset;
     if (index > size) {
-        ALOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, size);
+        ALOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, (int)size);
         *outValue = 0;
         return NO_ERROR;
     }
@@ -659,6 +659,16 @@
     return NULL;
 }
 
+const String8 ResStringPool::string8ObjectAt(size_t idx) const
+{
+    size_t len;
+    const char *str = (const char*)string8At(idx, &len);
+    if (str != NULL) {
+        return String8(str);
+    }
+    return String8(stringAt(idx, &len));
+}
+
 const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
 {
     return styleAt(ref.index);
@@ -738,12 +748,25 @@
     return (mError == NO_ERROR) ? mHeader->stringCount : 0;
 }
 
-#ifndef HAVE_ANDROID_OS
+size_t ResStringPool::styleCount() const
+{
+    return (mError == NO_ERROR) ? mHeader->styleCount : 0;
+}
+
+size_t ResStringPool::bytes() const
+{
+    return (mError == NO_ERROR) ? mHeader->header.size : 0;
+}
+
+bool ResStringPool::isSorted() const
+{
+    return (mHeader->flags&ResStringPool_header::SORTED_FLAG)!=0;
+}
+
 bool ResStringPool::isUTF8() const
 {
     return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0;
 }
-#endif
 
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
@@ -1367,6 +1390,873 @@
 // --------------------------------------------------------------------
 // --------------------------------------------------------------------
 
+void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) {
+    const size_t size = dtohl(o.size);
+    if (size >= sizeof(ResTable_config)) {
+        *this = o;
+    } else {
+        memcpy(this, &o, size);
+        memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
+    }
+}
+
+void ResTable_config::copyFromDtoH(const ResTable_config& o) {
+    copyFromDeviceNoSwap(o);
+    size = sizeof(ResTable_config);
+    mcc = dtohs(mcc);
+    mnc = dtohs(mnc);
+    density = dtohs(density);
+    screenWidth = dtohs(screenWidth);
+    screenHeight = dtohs(screenHeight);
+    sdkVersion = dtohs(sdkVersion);
+    minorVersion = dtohs(minorVersion);
+    smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
+    screenWidthDp = dtohs(screenWidthDp);
+    screenHeightDp = dtohs(screenHeightDp);
+}
+
+void ResTable_config::swapHtoD() {
+    size = htodl(size);
+    mcc = htods(mcc);
+    mnc = htods(mnc);
+    density = htods(density);
+    screenWidth = htods(screenWidth);
+    screenHeight = htods(screenHeight);
+    sdkVersion = htods(sdkVersion);
+    minorVersion = htods(minorVersion);
+    smallestScreenWidthDp = htods(smallestScreenWidthDp);
+    screenWidthDp = htods(screenWidthDp);
+    screenHeightDp = htods(screenHeightDp);
+}
+
+int ResTable_config::compare(const ResTable_config& o) const {
+    int32_t diff = (int32_t)(imsi - o.imsi);
+    if (diff != 0) return diff;
+    diff = (int32_t)(locale - o.locale);
+    if (diff != 0) return diff;
+    diff = (int32_t)(screenType - o.screenType);
+    if (diff != 0) return diff;
+    diff = (int32_t)(input - o.input);
+    if (diff != 0) return diff;
+    diff = (int32_t)(screenSize - o.screenSize);
+    if (diff != 0) return diff;
+    diff = (int32_t)(version - o.version);
+    if (diff != 0) return diff;
+    diff = (int32_t)(screenLayout - o.screenLayout);
+    if (diff != 0) return diff;
+    diff = (int32_t)(uiMode - o.uiMode);
+    if (diff != 0) return diff;
+    diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
+    if (diff != 0) return diff;
+    diff = (int32_t)(screenSizeDp - o.screenSizeDp);
+    return (int)diff;
+}
+
+int ResTable_config::compareLogical(const ResTable_config& o) const {
+    if (mcc != o.mcc) {
+        return mcc < o.mcc ? -1 : 1;
+    }
+    if (mnc != o.mnc) {
+        return mnc < o.mnc ? -1 : 1;
+    }
+    if (language[0] != o.language[0]) {
+        return language[0] < o.language[0] ? -1 : 1;
+    }
+    if (language[1] != o.language[1]) {
+        return language[1] < o.language[1] ? -1 : 1;
+    }
+    if (country[0] != o.country[0]) {
+        return country[0] < o.country[0] ? -1 : 1;
+    }
+    if (country[1] != o.country[1]) {
+        return country[1] < o.country[1] ? -1 : 1;
+    }
+    if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
+        return smallestScreenWidthDp < o.smallestScreenWidthDp ? -1 : 1;
+    }
+    if (screenWidthDp != o.screenWidthDp) {
+        return screenWidthDp < o.screenWidthDp ? -1 : 1;
+    }
+    if (screenHeightDp != o.screenHeightDp) {
+        return screenHeightDp < o.screenHeightDp ? -1 : 1;
+    }
+    if (screenWidth != o.screenWidth) {
+        return screenWidth < o.screenWidth ? -1 : 1;
+    }
+    if (screenHeight != o.screenHeight) {
+        return screenHeight < o.screenHeight ? -1 : 1;
+    }
+    if (density != o.density) {
+        return density < o.density ? -1 : 1;
+    }
+    if (orientation != o.orientation) {
+        return orientation < o.orientation ? -1 : 1;
+    }
+    if (touchscreen != o.touchscreen) {
+        return touchscreen < o.touchscreen ? -1 : 1;
+    }
+    if (input != o.input) {
+        return input < o.input ? -1 : 1;
+    }
+    if (screenLayout != o.screenLayout) {
+        return screenLayout < o.screenLayout ? -1 : 1;
+    }
+    if (uiMode != o.uiMode) {
+        return uiMode < o.uiMode ? -1 : 1;
+    }
+    if (version != o.version) {
+        return version < o.version ? -1 : 1;
+    }
+    return 0;
+}
+
+int ResTable_config::diff(const ResTable_config& o) const {
+    int diffs = 0;
+    if (mcc != o.mcc) diffs |= CONFIG_MCC;
+    if (mnc != o.mnc) diffs |= CONFIG_MNC;
+    if (locale != o.locale) diffs |= CONFIG_LOCALE;
+    if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
+    if (density != o.density) diffs |= CONFIG_DENSITY;
+    if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
+    if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
+            diffs |= CONFIG_KEYBOARD_HIDDEN;
+    if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
+    if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
+    if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
+    if (version != o.version) diffs |= CONFIG_VERSION;
+    if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT;
+    if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
+    if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
+    if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
+    return diffs;
+}
+
+bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
+    // The order of the following tests defines the importance of one
+    // configuration parameter over another.  Those tests first are more
+    // important, trumping any values in those following them.
+    if (imsi || o.imsi) {
+        if (mcc != o.mcc) {
+            if (!mcc) return false;
+            if (!o.mcc) return true;
+        }
+
+        if (mnc != o.mnc) {
+            if (!mnc) return false;
+            if (!o.mnc) return true;
+        }
+    }
+
+    if (locale || o.locale) {
+        if (language[0] != o.language[0]) {
+            if (!language[0]) return false;
+            if (!o.language[0]) return true;
+        }
+
+        if (country[0] != o.country[0]) {
+            if (!country[0]) return false;
+            if (!o.country[0]) return true;
+        }
+    }
+
+    if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
+        if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
+            if (!smallestScreenWidthDp) return false;
+            if (!o.smallestScreenWidthDp) return true;
+        }
+    }
+
+    if (screenSizeDp || o.screenSizeDp) {
+        if (screenWidthDp != o.screenWidthDp) {
+            if (!screenWidthDp) return false;
+            if (!o.screenWidthDp) return true;
+        }
+
+        if (screenHeightDp != o.screenHeightDp) {
+            if (!screenHeightDp) return false;
+            if (!o.screenHeightDp) return true;
+        }
+    }
+
+    if (screenLayout || o.screenLayout) {
+        if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
+            if (!(screenLayout & MASK_SCREENSIZE)) return false;
+            if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
+        }
+        if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
+            if (!(screenLayout & MASK_SCREENLONG)) return false;
+            if (!(o.screenLayout & MASK_SCREENLONG)) return true;
+        }
+    }
+
+    if (orientation != o.orientation) {
+        if (!orientation) return false;
+        if (!o.orientation) return true;
+    }
+
+    if (uiMode || o.uiMode) {
+        if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) {
+            if (!(uiMode & MASK_UI_MODE_TYPE)) return false;
+            if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true;
+        }
+        if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) {
+            if (!(uiMode & MASK_UI_MODE_NIGHT)) return false;
+            if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true;
+        }
+    }
+
+    // density is never 'more specific'
+    // as the default just equals 160
+
+    if (touchscreen != o.touchscreen) {
+        if (!touchscreen) return false;
+        if (!o.touchscreen) return true;
+    }
+
+    if (input || o.input) {
+        if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) {
+            if (!(inputFlags & MASK_KEYSHIDDEN)) return false;
+            if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
+        }
+
+        if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
+            if (!(inputFlags & MASK_NAVHIDDEN)) return false;
+            if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
+        }
+
+        if (keyboard != o.keyboard) {
+            if (!keyboard) return false;
+            if (!o.keyboard) return true;
+        }
+
+        if (navigation != o.navigation) {
+            if (!navigation) return false;
+            if (!o.navigation) return true;
+        }
+    }
+
+    if (screenSize || o.screenSize) {
+        if (screenWidth != o.screenWidth) {
+            if (!screenWidth) return false;
+            if (!o.screenWidth) return true;
+        }
+
+        if (screenHeight != o.screenHeight) {
+            if (!screenHeight) return false;
+            if (!o.screenHeight) return true;
+        }
+    }
+
+    if (version || o.version) {
+        if (sdkVersion != o.sdkVersion) {
+            if (!sdkVersion) return false;
+            if (!o.sdkVersion) return true;
+        }
+
+        if (minorVersion != o.minorVersion) {
+            if (!minorVersion) return false;
+            if (!o.minorVersion) return true;
+        }
+    }
+    return false;
+}
+
+bool ResTable_config::isBetterThan(const ResTable_config& o,
+        const ResTable_config* requested) const {
+    if (requested) {
+        if (imsi || o.imsi) {
+            if ((mcc != o.mcc) && requested->mcc) {
+                return (mcc);
+            }
+
+            if ((mnc != o.mnc) && requested->mnc) {
+                return (mnc);
+            }
+        }
+
+        if (locale || o.locale) {
+            if ((language[0] != o.language[0]) && requested->language[0]) {
+                return (language[0]);
+            }
+
+            if ((country[0] != o.country[0]) && requested->country[0]) {
+                return (country[0]);
+            }
+        }
+
+        if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
+            // The configuration closest to the actual size is best.
+            // We assume that larger configs have already been filtered
+            // out at this point.  That means we just want the largest one.
+            return smallestScreenWidthDp >= o.smallestScreenWidthDp;
+        }
+
+        if (screenSizeDp || o.screenSizeDp) {
+            // "Better" is based on the sum of the difference between both
+            // width and height from the requested dimensions.  We are
+            // assuming the invalid configs (with smaller dimens) have
+            // already been filtered.  Note that if a particular dimension
+            // is unspecified, we will end up with a large value (the
+            // difference between 0 and the requested dimension), which is
+            // good since we will prefer a config that has specified a
+            // dimension value.
+            int myDelta = 0, otherDelta = 0;
+            if (requested->screenWidthDp) {
+                myDelta += requested->screenWidthDp - screenWidthDp;
+                otherDelta += requested->screenWidthDp - o.screenWidthDp;
+            }
+            if (requested->screenHeightDp) {
+                myDelta += requested->screenHeightDp - screenHeightDp;
+                otherDelta += requested->screenHeightDp - o.screenHeightDp;
+            }
+            //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
+            //    screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
+            //    requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
+            return (myDelta <= otherDelta);
+        }
+
+        if (screenLayout || o.screenLayout) {
+            if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
+                    && (requested->screenLayout & MASK_SCREENSIZE)) {
+                // A little backwards compatibility here: undefined is
+                // considered equivalent to normal.  But only if the
+                // requested size is at least normal; otherwise, small
+                // is better than the default.
+                int mySL = (screenLayout & MASK_SCREENSIZE);
+                int oSL = (o.screenLayout & MASK_SCREENSIZE);
+                int fixedMySL = mySL;
+                int fixedOSL = oSL;
+                if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
+                    if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
+                    if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
+                }
+                // For screen size, the best match is the one that is
+                // closest to the requested screen size, but not over
+                // (the not over part is dealt with in match() below).
+                if (fixedMySL == fixedOSL) {
+                    // If the two are the same, but 'this' is actually
+                    // undefined, then the other is really a better match.
+                    if (mySL == 0) return false;
+                    return true;
+                }
+                return fixedMySL >= fixedOSL;
+            }
+            if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
+                    && (requested->screenLayout & MASK_SCREENLONG)) {
+                return (screenLayout & MASK_SCREENLONG);
+            }
+        }
+
+        if ((orientation != o.orientation) && requested->orientation) {
+            return (orientation);
+        }
+
+        if (uiMode || o.uiMode) {
+            if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
+                    && (requested->uiMode & MASK_UI_MODE_TYPE)) {
+                return (uiMode & MASK_UI_MODE_TYPE);
+            }
+            if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
+                    && (requested->uiMode & MASK_UI_MODE_NIGHT)) {
+                return (uiMode & MASK_UI_MODE_NIGHT);
+            }
+        }
+
+        if (screenType || o.screenType) {
+            if (density != o.density) {
+                // density is tough.  Any density is potentially useful
+                // because the system will scale it.  Scaling down
+                // is generally better than scaling up.
+                // Default density counts as 160dpi (the system default)
+                // TODO - remove 160 constants
+                int h = (density?density:160);
+                int l = (o.density?o.density:160);
+                bool bImBigger = true;
+                if (l > h) {
+                    int t = h;
+                    h = l;
+                    l = t;
+                    bImBigger = false;
+                }
+
+                int reqValue = (requested->density?requested->density:160);
+                if (reqValue >= h) {
+                    // requested value higher than both l and h, give h
+                    return bImBigger;
+                }
+                if (l >= reqValue) {
+                    // requested value lower than both l and h, give l
+                    return !bImBigger;
+                }
+                // saying that scaling down is 2x better than up
+                if (((2 * l) - reqValue) * h > reqValue * reqValue) {
+                    return !bImBigger;
+                } else {
+                    return bImBigger;
+                }
+            }
+
+            if ((touchscreen != o.touchscreen) && requested->touchscreen) {
+                return (touchscreen);
+            }
+        }
+
+        if (input || o.input) {
+            const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
+            const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
+            if (keysHidden != oKeysHidden) {
+                const int reqKeysHidden =
+                        requested->inputFlags & MASK_KEYSHIDDEN;
+                if (reqKeysHidden) {
+
+                    if (!keysHidden) return false;
+                    if (!oKeysHidden) return true;
+                    // For compatibility, we count KEYSHIDDEN_NO as being
+                    // the same as KEYSHIDDEN_SOFT.  Here we disambiguate
+                    // these by making an exact match more specific.
+                    if (reqKeysHidden == keysHidden) return true;
+                    if (reqKeysHidden == oKeysHidden) return false;
+                }
+            }
+
+            const int navHidden = inputFlags & MASK_NAVHIDDEN;
+            const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
+            if (navHidden != oNavHidden) {
+                const int reqNavHidden =
+                        requested->inputFlags & MASK_NAVHIDDEN;
+                if (reqNavHidden) {
+
+                    if (!navHidden) return false;
+                    if (!oNavHidden) return true;
+                }
+            }
+
+            if ((keyboard != o.keyboard) && requested->keyboard) {
+                return (keyboard);
+            }
+
+            if ((navigation != o.navigation) && requested->navigation) {
+                return (navigation);
+            }
+        }
+
+        if (screenSize || o.screenSize) {
+            // "Better" is based on the sum of the difference between both
+            // width and height from the requested dimensions.  We are
+            // assuming the invalid configs (with smaller sizes) have
+            // already been filtered.  Note that if a particular dimension
+            // is unspecified, we will end up with a large value (the
+            // difference between 0 and the requested dimension), which is
+            // good since we will prefer a config that has specified a
+            // size value.
+            int myDelta = 0, otherDelta = 0;
+            if (requested->screenWidth) {
+                myDelta += requested->screenWidth - screenWidth;
+                otherDelta += requested->screenWidth - o.screenWidth;
+            }
+            if (requested->screenHeight) {
+                myDelta += requested->screenHeight - screenHeight;
+                otherDelta += requested->screenHeight - o.screenHeight;
+            }
+            return (myDelta <= otherDelta);
+        }
+
+        if (version || o.version) {
+            if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
+                return (sdkVersion > o.sdkVersion);
+            }
+
+            if ((minorVersion != o.minorVersion) &&
+                    requested->minorVersion) {
+                return (minorVersion);
+            }
+        }
+
+        return false;
+    }
+    return isMoreSpecificThan(o);
+}
+
+bool ResTable_config::match(const ResTable_config& settings) const {
+    if (imsi != 0) {
+        if (mcc != 0 && mcc != settings.mcc) {
+            return false;
+        }
+        if (mnc != 0 && mnc != settings.mnc) {
+            return false;
+        }
+    }
+    if (locale != 0) {
+        if (language[0] != 0
+            && (language[0] != settings.language[0]
+                || language[1] != settings.language[1])) {
+            return false;
+        }
+        if (country[0] != 0
+            && (country[0] != settings.country[0]
+                || country[1] != settings.country[1])) {
+            return false;
+        }
+    }
+    if (screenConfig != 0) {
+        const int screenSize = screenLayout&MASK_SCREENSIZE;
+        const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
+        // Any screen sizes for larger screens than the setting do not
+        // match.
+        if (screenSize != 0 && screenSize > setScreenSize) {
+            return false;
+        }
+
+        const int screenLong = screenLayout&MASK_SCREENLONG;
+        const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
+        if (screenLong != 0 && screenLong != setScreenLong) {
+            return false;
+        }
+
+        const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
+        const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
+        if (uiModeType != 0 && uiModeType != setUiModeType) {
+            return false;
+        }
+
+        const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
+        const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
+        if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
+            return false;
+        }
+
+        if (smallestScreenWidthDp != 0
+                && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
+            return false;
+        }
+    }
+    if (screenSizeDp != 0) {
+        if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
+            //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
+            return false;
+        }
+        if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
+            //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
+            return false;
+        }
+    }
+    if (screenType != 0) {
+        if (orientation != 0 && orientation != settings.orientation) {
+            return false;
+        }
+        // density always matches - we can scale it.  See isBetterThan
+        if (touchscreen != 0 && touchscreen != settings.touchscreen) {
+            return false;
+        }
+    }
+    if (input != 0) {
+        const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
+        const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
+        if (keysHidden != 0 && keysHidden != setKeysHidden) {
+            // For compatibility, we count a request for KEYSHIDDEN_NO as also
+            // matching the more recent KEYSHIDDEN_SOFT.  Basically
+            // KEYSHIDDEN_NO means there is some kind of keyboard available.
+            //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
+            if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
+                //ALOGI("No match!");
+                return false;
+            }
+        }
+        const int navHidden = inputFlags&MASK_NAVHIDDEN;
+        const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
+        if (navHidden != 0 && navHidden != setNavHidden) {
+            return false;
+        }
+        if (keyboard != 0 && keyboard != settings.keyboard) {
+            return false;
+        }
+        if (navigation != 0 && navigation != settings.navigation) {
+            return false;
+        }
+    }
+    if (screenSize != 0) {
+        if (screenWidth != 0 && screenWidth > settings.screenWidth) {
+            return false;
+        }
+        if (screenHeight != 0 && screenHeight > settings.screenHeight) {
+            return false;
+        }
+    }
+    if (version != 0) {
+        if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
+            return false;
+        }
+        if (minorVersion != 0 && minorVersion != settings.minorVersion) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void ResTable_config::getLocale(char str[6]) const {
+    memset(str, 0, 6);
+    if (language[0]) {
+        str[0] = language[0];
+        str[1] = language[1];
+        if (country[0]) {
+            str[2] = '_';
+            str[3] = country[0];
+            str[4] = country[1];
+        }
+    }
+}
+
+String8 ResTable_config::toString() const {
+    String8 res;
+
+    if (mcc != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("%dmcc", dtohs(mcc));
+    }
+    if (mnc != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("%dmnc", dtohs(mnc));
+    }
+    if (language[0] != 0) {
+        if (res.size() > 0) res.append("-");
+        res.append(language, 2);
+    }
+    if (country[0] != 0) {
+        if (res.size() > 0) res.append("-");
+        res.append(country, 2);
+    }
+    if (smallestScreenWidthDp != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("sw%ddp", dtohs(smallestScreenWidthDp));
+    }
+    if (screenWidthDp != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("w%ddp", dtohs(screenWidthDp));
+    }
+    if (screenHeightDp != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("h%ddp", dtohs(screenHeightDp));
+    }
+    if ((screenLayout&MASK_SCREENSIZE) != SCREENSIZE_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (screenLayout&ResTable_config::MASK_SCREENSIZE) {
+            case ResTable_config::SCREENSIZE_SMALL:
+                res.append("small");
+                break;
+            case ResTable_config::SCREENSIZE_NORMAL:
+                res.append("normal");
+                break;
+            case ResTable_config::SCREENSIZE_LARGE:
+                res.append("large");
+                break;
+            case ResTable_config::SCREENSIZE_XLARGE:
+                res.append("xlarge");
+                break;
+            default:
+                res.appendFormat("screenLayoutSize=%d",
+                        dtohs(screenLayout&ResTable_config::MASK_SCREENSIZE));
+                break;
+        }
+    }
+    if ((screenLayout&MASK_SCREENLONG) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (screenLayout&ResTable_config::MASK_SCREENLONG) {
+            case ResTable_config::SCREENLONG_NO:
+                res.append("notlong");
+                break;
+            case ResTable_config::SCREENLONG_YES:
+                res.append("long");
+                break;
+            default:
+                res.appendFormat("screenLayoutLong=%d",
+                        dtohs(screenLayout&ResTable_config::MASK_SCREENLONG));
+                break;
+        }
+    }
+    if (orientation != ORIENTATION_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (orientation) {
+            case ResTable_config::ORIENTATION_PORT:
+                res.append("port");
+                break;
+            case ResTable_config::ORIENTATION_LAND:
+                res.append("land");
+                break;
+            case ResTable_config::ORIENTATION_SQUARE:
+                res.append("square");
+                break;
+            default:
+                res.appendFormat("orientation=%d", dtohs(orientation));
+                break;
+        }
+    }
+    if ((uiMode&MASK_UI_MODE_TYPE) != UI_MODE_TYPE_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (uiMode&ResTable_config::MASK_UI_MODE_TYPE) {
+            case ResTable_config::UI_MODE_TYPE_DESK:
+                res.append("desk");
+                break;
+            case ResTable_config::UI_MODE_TYPE_CAR:
+                res.append("car");
+                break;
+            case ResTable_config::UI_MODE_TYPE_TELEVISION:
+                res.append("television");
+                break;
+            case ResTable_config::UI_MODE_TYPE_APPLIANCE:
+                res.append("appliance");
+                break;
+            default:
+                res.appendFormat("uiModeType=%d",
+                        dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE));
+                break;
+        }
+    }
+    if ((uiMode&MASK_UI_MODE_NIGHT) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
+            case ResTable_config::UI_MODE_NIGHT_NO:
+                res.append("notnight");
+                break;
+            case ResTable_config::UI_MODE_NIGHT_YES:
+                res.append("night");
+                break;
+            default:
+                res.appendFormat("uiModeNight=%d",
+                        dtohs(uiMode&MASK_UI_MODE_NIGHT));
+                break;
+        }
+    }
+    if (density != DENSITY_DEFAULT) {
+        if (res.size() > 0) res.append("-");
+        switch (density) {
+            case ResTable_config::DENSITY_LOW:
+                res.append("ldpi");
+                break;
+            case ResTable_config::DENSITY_MEDIUM:
+                res.append("mdpi");
+                break;
+            case ResTable_config::DENSITY_TV:
+                res.append("tvdpi");
+                break;
+            case ResTable_config::DENSITY_HIGH:
+                res.append("hdpi");
+                break;
+            case ResTable_config::DENSITY_XHIGH:
+                res.append("xhdpi");
+                break;
+            case ResTable_config::DENSITY_XXHIGH:
+                res.append("xxhdpi");
+                break;
+            case ResTable_config::DENSITY_NONE:
+                res.append("nodpi");
+                break;
+            default:
+                res.appendFormat("density=%d", dtohs(density));
+                break;
+        }
+    }
+    if (touchscreen != TOUCHSCREEN_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (touchscreen) {
+            case ResTable_config::TOUCHSCREEN_NOTOUCH:
+                res.append("notouch");
+                break;
+            case ResTable_config::TOUCHSCREEN_FINGER:
+                res.append("finger");
+                break;
+            case ResTable_config::TOUCHSCREEN_STYLUS:
+                res.append("stylus");
+                break;
+            default:
+                res.appendFormat("touchscreen=%d", dtohs(touchscreen));
+                break;
+        }
+    }
+    if (keyboard != KEYBOARD_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (keyboard) {
+            case ResTable_config::KEYBOARD_NOKEYS:
+                res.append("nokeys");
+                break;
+            case ResTable_config::KEYBOARD_QWERTY:
+                res.append("qwerty");
+                break;
+            case ResTable_config::KEYBOARD_12KEY:
+                res.append("12key");
+                break;
+            default:
+                res.appendFormat("keyboard=%d", dtohs(keyboard));
+                break;
+        }
+    }
+    if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (inputFlags&MASK_KEYSHIDDEN) {
+            case ResTable_config::KEYSHIDDEN_NO:
+                res.append("keysexposed");
+                break;
+            case ResTable_config::KEYSHIDDEN_YES:
+                res.append("keyshidden");
+                break;
+            case ResTable_config::KEYSHIDDEN_SOFT:
+                res.append("keyssoft");
+                break;
+        }
+    }
+    if (navigation != NAVIGATION_ANY) {
+        if (res.size() > 0) res.append("-");
+        switch (navigation) {
+            case ResTable_config::NAVIGATION_NONAV:
+                res.append("nonav");
+                break;
+            case ResTable_config::NAVIGATION_DPAD:
+                res.append("dpad");
+                break;
+            case ResTable_config::NAVIGATION_TRACKBALL:
+                res.append("trackball");
+                break;
+            case ResTable_config::NAVIGATION_WHEEL:
+                res.append("wheel");
+                break;
+            default:
+                res.appendFormat("navigation=%d", dtohs(navigation));
+                break;
+        }
+    }
+    if ((inputFlags&MASK_NAVHIDDEN) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (inputFlags&MASK_NAVHIDDEN) {
+            case ResTable_config::NAVHIDDEN_NO:
+                res.append("navsexposed");
+                break;
+            case ResTable_config::NAVHIDDEN_YES:
+                res.append("navhidden");
+                break;
+            default:
+                res.appendFormat("inputFlagsNavHidden=%d",
+                        dtohs(inputFlags&MASK_NAVHIDDEN));
+                break;
+        }
+    }
+    if (screenSize != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight));
+    }
+    if (version != 0) {
+        if (res.size() > 0) res.append("-");
+        res.appendFormat("v%d", dtohs(sdkVersion));
+        if (minorVersion != 0) {
+            res.appendFormat(".%d", dtohs(minorVersion));
+        }
+    }
+
+    return res;
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+
 struct ResTable::Header
 {
     Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
@@ -3953,43 +4843,9 @@
         ResTable_config thisConfig;
         thisConfig.copyFromDtoH(thisType->config);
 
-        TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d "
-                            "lang:%c%c=%c%c cnt:%c%c=%c%c orien:%d=%d touch:%d=%d "
-                            "density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d "
-                            "swdp:%d=%d wdp:%d=%d hdp:%d=%d\n",
+        TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): %s\n",
                            entryIndex, typeIndex+1, dtohl(thisType->config.size),
-                           thisConfig.mcc, thisConfig.mnc,
-                           config ? config->mcc : 0, config ? config->mnc : 0,
-                           thisConfig.language[0] ? thisConfig.language[0] : '-',
-                           thisConfig.language[1] ? thisConfig.language[1] : '-',
-                           config && config->language[0] ? config->language[0] : '-',
-                           config && config->language[1] ? config->language[1] : '-',
-                           thisConfig.country[0] ? thisConfig.country[0] : '-',
-                           thisConfig.country[1] ? thisConfig.country[1] : '-',
-                           config && config->country[0] ? config->country[0] : '-',
-                           config && config->country[1] ? config->country[1] : '-',
-                           thisConfig.orientation,
-                           config ? config->orientation : 0,
-                           thisConfig.touchscreen,
-                           config ? config->touchscreen : 0,
-                           thisConfig.density,
-                           config ? config->density : 0,
-                           thisConfig.keyboard,
-                           config ? config->keyboard : 0,
-                           thisConfig.inputFlags,
-                           config ? config->inputFlags : 0,
-                           thisConfig.navigation,
-                           config ? config->navigation : 0,
-                           thisConfig.screenWidth,
-                           config ? config->screenWidth : 0,
-                           thisConfig.screenHeight,
-                           config ? config->screenHeight : 0,
-                           thisConfig.smallestScreenWidthDp,
-                           config ? config->smallestScreenWidthDp : 0,
-                           thisConfig.screenWidthDp,
-                           config ? config->screenWidthDp : 0,
-                           thisConfig.screenHeightDp,
-                           config ? config->screenHeightDp : 0));
+                           thisConfig.toString().string()));
         
         // Check to make sure this one is valid for the current parameters.
         if (config && !thisConfig.match(*config)) {
@@ -4273,26 +5129,8 @@
             TABLE_GETENTRY(
                 ResTable_config thisConfig;
                 thisConfig.copyFromDtoH(type->config);
-                ALOGI("Adding config to type %d: imsi:%d/%d lang:%c%c cnt:%c%c "
-                     "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d "
-                     "swdp:%d wdp:%d hdp:%d\n",
-                      type->id,
-                      thisConfig.mcc, thisConfig.mnc,
-                      thisConfig.language[0] ? thisConfig.language[0] : '-',
-                      thisConfig.language[1] ? thisConfig.language[1] : '-',
-                      thisConfig.country[0] ? thisConfig.country[0] : '-',
-                      thisConfig.country[1] ? thisConfig.country[1] : '-',
-                      thisConfig.orientation,
-                      thisConfig.touchscreen,
-                      thisConfig.density,
-                      thisConfig.keyboard,
-                      thisConfig.inputFlags,
-                      thisConfig.navigation,
-                      thisConfig.screenWidth,
-                      thisConfig.screenHeight,
-                      thisConfig.smallestScreenWidthDp,
-                      thisConfig.screenWidthDp,
-                      thisConfig.screenHeightDp));
+                ALOGI("Adding config to type %d: %s\n",
+                      type->id, thisConfig.toString().string()));
             t->configs.add(type);
         } else {
             status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
@@ -4622,186 +5460,9 @@
                         printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
                         continue;
                     }
-                    char density[16];
-                    uint16_t dval = dtohs(type->config.density);
-                    if (dval == ResTable_config::DENSITY_DEFAULT) {
-                        strcpy(density, "def");
-                    } else if (dval == ResTable_config::DENSITY_NONE) {
-                        strcpy(density, "no");
-                    } else {
-                        sprintf(density, "%d", (int)dval);
-                    }
-                    printf("      config %d", (int)configIndex);
-                    if (type->config.mcc != 0) {
-                        printf(" mcc=%d", dtohs(type->config.mcc));
-                    }
-                    if (type->config.mnc != 0) {
-                        printf(" mnc=%d", dtohs(type->config.mnc));
-                    }
-                    if (type->config.locale != 0) {
-                        printf(" lang=%c%c cnt=%c%c",
-                               type->config.language[0] ? type->config.language[0] : '-',
-                               type->config.language[1] ? type->config.language[1] : '-',
-                               type->config.country[0] ? type->config.country[0] : '-',
-                               type->config.country[1] ? type->config.country[1] : '-');
-                    }
-                    if (type->config.screenLayout != 0) {
-                        printf(" sz=%d",
-                                type->config.screenLayout&ResTable_config::MASK_SCREENSIZE);
-                        switch (type->config.screenLayout&ResTable_config::MASK_SCREENSIZE) {
-                            case ResTable_config::SCREENSIZE_SMALL:
-                                printf(" (small)");
-                                break;
-                            case ResTable_config::SCREENSIZE_NORMAL:
-                                printf(" (normal)");
-                                break;
-                            case ResTable_config::SCREENSIZE_LARGE:
-                                printf(" (large)");
-                                break;
-                            case ResTable_config::SCREENSIZE_XLARGE:
-                                printf(" (xlarge)");
-                                break;
-                        }
-                        printf(" lng=%d",
-                                type->config.screenLayout&ResTable_config::MASK_SCREENLONG);
-                        switch (type->config.screenLayout&ResTable_config::MASK_SCREENLONG) {
-                            case ResTable_config::SCREENLONG_NO:
-                                printf(" (notlong)");
-                                break;
-                            case ResTable_config::SCREENLONG_YES:
-                                printf(" (long)");
-                                break;
-                        }
-                    }
-                    if (type->config.orientation != 0) {
-                        printf(" orient=%d", type->config.orientation);
-                        switch (type->config.orientation) {
-                            case ResTable_config::ORIENTATION_PORT:
-                                printf(" (port)");
-                                break;
-                            case ResTable_config::ORIENTATION_LAND:
-                                printf(" (land)");
-                                break;
-                            case ResTable_config::ORIENTATION_SQUARE:
-                                printf(" (square)");
-                                break;
-                        }
-                    }
-                    if (type->config.uiMode != 0) {
-                        printf(" type=%d",
-                                type->config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
-                        switch (type->config.uiMode&ResTable_config::MASK_UI_MODE_TYPE) {
-                            case ResTable_config::UI_MODE_TYPE_NORMAL:
-                                printf(" (normal)");
-                                break;
-                            case ResTable_config::UI_MODE_TYPE_CAR:
-                                printf(" (car)");
-                                break;
-                        }
-                        printf(" night=%d",
-                                type->config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
-                        switch (type->config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
-                            case ResTable_config::UI_MODE_NIGHT_NO:
-                                printf(" (no)");
-                                break;
-                            case ResTable_config::UI_MODE_NIGHT_YES:
-                                printf(" (yes)");
-                                break;
-                        }
-                    }
-                    if (dval != 0) {
-                        printf(" density=%s", density);
-                    }
-                    if (type->config.touchscreen != 0) {
-                        printf(" touch=%d", type->config.touchscreen);
-                        switch (type->config.touchscreen) {
-                            case ResTable_config::TOUCHSCREEN_NOTOUCH:
-                                printf(" (notouch)");
-                                break;
-                            case ResTable_config::TOUCHSCREEN_STYLUS:
-                                printf(" (stylus)");
-                                break;
-                            case ResTable_config::TOUCHSCREEN_FINGER:
-                                printf(" (finger)");
-                                break;
-                        }
-                    }
-                    if (type->config.inputFlags != 0) {
-                        printf(" keyhid=%d", type->config.inputFlags&ResTable_config::MASK_KEYSHIDDEN);
-                        switch (type->config.inputFlags&ResTable_config::MASK_KEYSHIDDEN) {
-                            case ResTable_config::KEYSHIDDEN_NO:
-                                printf(" (no)");
-                                break;
-                            case ResTable_config::KEYSHIDDEN_YES:
-                                printf(" (yes)");
-                                break;
-                            case ResTable_config::KEYSHIDDEN_SOFT:
-                                printf(" (soft)");
-                                break;
-                        }
-                        printf(" navhid=%d", type->config.inputFlags&ResTable_config::MASK_NAVHIDDEN);
-                        switch (type->config.inputFlags&ResTable_config::MASK_NAVHIDDEN) {
-                            case ResTable_config::NAVHIDDEN_NO:
-                                printf(" (no)");
-                                break;
-                            case ResTable_config::NAVHIDDEN_YES:
-                                printf(" (yes)");
-                                break;
-                        }
-                    }
-                    if (type->config.keyboard != 0) {
-                        printf(" kbd=%d", type->config.keyboard);
-                        switch (type->config.keyboard) {
-                            case ResTable_config::KEYBOARD_NOKEYS:
-                                printf(" (nokeys)");
-                                break;
-                            case ResTable_config::KEYBOARD_QWERTY:
-                                printf(" (qwerty)");
-                                break;
-                            case ResTable_config::KEYBOARD_12KEY:
-                                printf(" (12key)");
-                                break;
-                        }
-                    }
-                    if (type->config.navigation != 0) {
-                        printf(" nav=%d", type->config.navigation);
-                        switch (type->config.navigation) {
-                            case ResTable_config::NAVIGATION_NONAV:
-                                printf(" (nonav)");
-                                break;
-                            case ResTable_config::NAVIGATION_DPAD:
-                                printf(" (dpad)");
-                                break;
-                            case ResTable_config::NAVIGATION_TRACKBALL:
-                                printf(" (trackball)");
-                                break;
-                            case ResTable_config::NAVIGATION_WHEEL:
-                                printf(" (wheel)");
-                                break;
-                        }
-                    }
-                    if (type->config.screenWidth != 0) {
-                        printf(" w=%d", dtohs(type->config.screenWidth));
-                    }
-                    if (type->config.screenHeight != 0) {
-                        printf(" h=%d", dtohs(type->config.screenHeight));
-                    }
-                    if (type->config.smallestScreenWidthDp != 0) {
-                        printf(" swdp=%d", dtohs(type->config.smallestScreenWidthDp));
-                    }
-                    if (type->config.screenWidthDp != 0) {
-                        printf(" wdp=%d", dtohs(type->config.screenWidthDp));
-                    }
-                    if (type->config.screenHeightDp != 0) {
-                        printf(" hdp=%d", dtohs(type->config.screenHeightDp));
-                    }
-                    if (type->config.sdkVersion != 0) {
-                        printf(" sdk=%d", dtohs(type->config.sdkVersion));
-                    }
-                    if (type->config.minorVersion != 0) {
-                        printf(" mver=%d", dtohs(type->config.minorVersion));
-                    }
-                    printf("\n");
+                    String8 configStr = type->config.toString();
+                    printf("      config %s:\n", configStr.size() > 0
+                            ? configStr.string() : "(default)");
                     size_t entryCount = dtohl(type->entryCount);
                     uint32_t entriesStart = dtohl(type->entriesStart);
                     if ((entriesStart&0x3) != 0) {
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index e343c62..ab207f5 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -34,6 +34,9 @@
 # include <pthread.h>
 # include <sched.h>
 # include <sys/resource.h>
+#ifdef HAVE_ANDROID_OS
+# include <bionic_pthread.h>
+#endif
 #elif defined(HAVE_WIN32_THREADS)
 # include <windows.h>
 # include <stdint.h>
@@ -86,7 +89,7 @@
     char *          threadName;
 
     // we use this trampoline when we need to set the priority with
-    // nice/setpriority.
+    // nice/setpriority, and name with prctl.
     static int trampoline(const thread_data_t* t) {
         thread_func_t f = t->entryFunction;
         void* u = t->userData;
@@ -141,8 +144,13 @@
 
 #ifdef HAVE_ANDROID_OS  /* valgrind is rejecting RT-priority create reqs */
     if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
-        // We could avoid the trampoline if there was a way to get to the
-        // android_thread_id_t (pid) from pthread_t
+        // Now that the pthread_t has a method to find the associated
+        // android_thread_id_t (pid) from pthread_t, it would be possible to avoid
+        // this trampoline in some cases as the parent could set the properties
+        // for the child.  However, there would be a race condition because the
+        // child becomes ready immediately, and it doesn't work for the name.
+        // prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was
+        // proposed but not yet accepted.
         thread_data_t* t = new thread_data_t;
         t->priority = threadPriority;
         t->threadName = threadName ? strdup(threadName) : NULL;
@@ -178,6 +186,13 @@
     return 1;
 }
 
+#ifdef HAVE_ANDROID_OS
+static pthread_t android_thread_id_t_to_pthread(android_thread_id_t thread)
+{
+    return (pthread_t) thread;
+}
+#endif
+
 android_thread_id_t androidGetThreadId()
 {
     return (android_thread_id_t)pthread_self();
@@ -909,6 +924,23 @@
     return mStatus;
 }
 
+#ifdef HAVE_ANDROID_OS
+pid_t Thread::getTid() const
+{
+    // mTid is not defined until the child initializes it, and the caller may need it earlier
+    Mutex::Autolock _l(mLock);
+    pid_t tid;
+    if (mRunning) {
+        pthread_t pthread = android_thread_id_t_to_pthread(mThread);
+        tid = __pthread_gettid(pthread);
+    } else {
+        ALOGW("Thread (this=%p): getTid() is undefined before run()", this);
+        tid = -1;
+    }
+    return tid;
+}
+#endif
+
 bool Thread::exitPending() const
 {
     Mutex::Autolock _l(mLock);
diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java
index bc68472..8b7eee2 100644
--- a/media/java/android/media/AmrInputStream.java
+++ b/media/java/android/media/AmrInputStream.java
@@ -44,7 +44,7 @@
     private int mGae;
     
     // result amr stream
-    private byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2];
+    private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2];
     private int mBufIn = 0;
     private int mBufOut = 0;
     
diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java
index 09aec2e..804528e 100644
--- a/media/java/android/media/AsyncPlayer.java
+++ b/media/java/android/media/AsyncPlayer.java
@@ -49,7 +49,7 @@
         }
     }
 
-    private LinkedList<Command> mCmdQueue = new LinkedList();
+    private final LinkedList<Command> mCmdQueue = new LinkedList();
 
     private void startSound(Command cmd) {
         // Preparing can be slow, so if there is something else
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 936ec0f..9748d3b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -48,6 +48,7 @@
     private final Context mContext;
     private long mVolumeKeyUpTime;
     private int  mVolumeControlStream = -1;
+    private final boolean mUseMasterVolume;
     private static String TAG = "AudioManager";
 
     /**
@@ -90,7 +91,8 @@
      * @see #EXTRA_VIBRATE_SETTING
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED";
+    public static final String VIBRATE_SETTING_CHANGED_ACTION =
+        "android.media.VIBRATE_SETTING_CHANGED";
 
     /**
      * @hide Broadcast intent when the volume for a particular stream type changes.
@@ -104,6 +106,27 @@
     public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
 
     /**
+     * @hide Broadcast intent when the master volume changes.
+     * Includes the new volume
+     *
+     * @see #EXTRA_MASTER_VOLUME_VALUE
+     * @see #EXTRA_PREV_MASTER_VOLUME_VALUE
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String MASTER_VOLUME_CHANGED_ACTION =
+        "android.media.MASTER_VOLUME_CHANGED_ACTION";
+
+    /**
+     * @hide Broadcast intent when the master mute state changes.
+     * Includes the the new volume
+     *
+     * @see #EXTRA_MASTER_VOLUME_MUTED
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String MASTER_MUTE_CHANGED_ACTION =
+        "android.media.MASTER_MUTE_CHANGED_ACTION";
+
+    /**
      * The new vibrate setting for a particular type.
      *
      * @see #VIBRATE_SETTING_CHANGED_ACTION
@@ -140,6 +163,27 @@
     public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
         "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
 
+    /**
+     * @hide The new master volume value for the master volume changed intent.
+     * Value is integer between 0 and 100 inclusive.
+     */
+    public static final String EXTRA_MASTER_VOLUME_VALUE =
+        "android.media.EXTRA_MASTER_VOLUME_VALUE";
+
+    /**
+     * @hide The previous master volume value for the master volume changed intent.
+     * Value is integer between 0 and 100 inclusive.
+     */
+    public static final String EXTRA_PREV_MASTER_VOLUME_VALUE =
+        "android.media.EXTRA_PREV_MASTER_VOLUME_VALUE";
+
+    /**
+     * @hide The new master volume mute state for the master mute changed intent.
+     * Value is boolean
+     */
+    public static final String EXTRA_MASTER_VOLUME_MUTED =
+        "android.media.EXTRA_MASTER_VOLUME_MUTED";
+
     /** The audio stream for phone calls */
     public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
     /** The audio stream for system sounds */
@@ -354,6 +398,8 @@
      */
     public AudioManager(Context context) {
         mContext = context;
+        mUseMasterVolume = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_useMasterVolume);
     }
 
     private static IAudioService getService()
@@ -369,11 +415,12 @@
     /**
      * @hide
      */
-    public void preDispatchKeyEvent(int keyCode, int stream) {
+    public void preDispatchKeyEvent(KeyEvent event, int stream) {
         /*
          * If the user hits another key within the play sound delay, then
          * cancel the sound
          */
+        int keyCode = event.getKeyCode();
         if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
                 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
                 && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY
@@ -382,15 +429,20 @@
              * The user has hit another key during the delay (e.g., 300ms)
              * since the last volume key up, so cancel any sounds.
              */
-            adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME,
+            if (mUseMasterVolume) {
+                adjustMasterVolume(ADJUST_SAME, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
+            } else {
+                adjustSuggestedStreamVolume(ADJUST_SAME,
                         stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
+            }
         }
     }
 
     /**
      * @hide
      */
-    public void handleKeyDown(int keyCode, int stream) {
+    public void handleKeyDown(KeyEvent event, int stream) {
+        int keyCode = event.getKeyCode();
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -399,19 +451,33 @@
                  * responsive to the user.
                  */
                 int flags = FLAG_SHOW_UI | FLAG_VIBRATE;
-                if (mVolumeControlStream != -1) {
-                    stream = mVolumeControlStream;
-                    flags |= FLAG_FORCE_STREAM;
+                if (mUseMasterVolume) {
+                    adjustMasterVolume(
+                            keyCode == KeyEvent.KEYCODE_VOLUME_UP
+                                    ? ADJUST_RAISE
+                                    : ADJUST_LOWER,
+                            flags);
+                } else {
+                    if (mVolumeControlStream != -1) {
+                        stream = mVolumeControlStream;
+                        flags |= FLAG_FORCE_STREAM;
+                    }
+                    adjustSuggestedStreamVolume(
+                            keyCode == KeyEvent.KEYCODE_VOLUME_UP
+                                    ? ADJUST_RAISE
+                                    : ADJUST_LOWER,
+                            stream,
+                            flags);
                 }
-                adjustSuggestedStreamVolume(
-                        keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                                ? ADJUST_RAISE
-                                : ADJUST_LOWER,
-                        stream,
-                        flags);
                 break;
             case KeyEvent.KEYCODE_VOLUME_MUTE:
-                // TODO: Actually handle MUTE.
+                if (event.getRepeatCount() == 0) {
+                    if (mUseMasterVolume) {
+                        setMasterMute(!isMasterMute());
+                    } else {
+                        // TODO: Actually handle MUTE.
+                    }
+                }
                 break;
         }
     }
@@ -419,7 +485,8 @@
     /**
      * @hide
      */
-    public void handleKeyUp(int keyCode, int stream) {
+    public void handleKeyUp(KeyEvent event, int stream) {
+        int keyCode = event.getKeyCode();
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -427,21 +494,24 @@
                  * Play a sound. This is done on key up since we don't want the
                  * sound to play when a user holds down volume down to mute.
                  */
-                int flags = FLAG_PLAY_SOUND;
-                if (mVolumeControlStream != -1) {
-                    stream = mVolumeControlStream;
-                    flags |= FLAG_FORCE_STREAM;
+                if (mUseMasterVolume) {
+                    if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+                        adjustMasterVolume(ADJUST_SAME, FLAG_PLAY_SOUND);
+                    }
+                } else {
+                    int flags = FLAG_PLAY_SOUND;
+                    if (mVolumeControlStream != -1) {
+                        stream = mVolumeControlStream;
+                        flags |= FLAG_FORCE_STREAM;
+                    }
+                    adjustSuggestedStreamVolume(
+                            ADJUST_SAME,
+                            stream,
+                            flags);
                 }
-                adjustSuggestedStreamVolume(
-                        ADJUST_SAME,
-                        stream,
-                        flags);
 
                 mVolumeKeyUpTime = SystemClock.uptimeMillis();
                 break;
-            case KeyEvent.KEYCODE_VOLUME_MUTE:
-                // TODO: Actually handle MUTE.
-                break;
         }
     }
 
@@ -464,7 +534,11 @@
     public void adjustStreamVolume(int streamType, int direction, int flags) {
         IAudioService service = getService();
         try {
-            service.adjustStreamVolume(streamType, direction, flags);
+            if (mUseMasterVolume) {
+                service.adjustMasterVolume(direction, flags);
+            } else {
+                service.adjustStreamVolume(streamType, direction, flags);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustStreamVolume", e);
         }
@@ -490,7 +564,11 @@
     public void adjustVolume(int direction, int flags) {
         IAudioService service = getService();
         try {
-            service.adjustVolume(direction, flags);
+            if (mUseMasterVolume) {
+                service.adjustMasterVolume(direction, flags);
+            } else {
+                service.adjustVolume(direction, flags);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustVolume", e);
         }
@@ -516,9 +594,32 @@
     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
         IAudioService service = getService();
         try {
-            service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+            if (mUseMasterVolume) {
+                service.adjustMasterVolume(direction, flags);
+            } else {
+                service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+            }
         } catch (RemoteException e) {
-            Log.e(TAG, "Dead object in adjustVolume", e);
+            Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
+        }
+    }
+
+    /**
+     * Adjusts the master volume for the device's audio amplifier.
+     * <p>
+     *
+     * @param direction The direction to adjust the volume. One of
+     *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
+     *            {@link #ADJUST_SAME}.
+     * @param flags One or more flags.
+     * @hide
+     */
+    public void adjustMasterVolume(int direction, int flags) {
+        IAudioService service = getService();
+        try {
+            service.adjustMasterVolume(direction, flags);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in adjustMasterVolume", e);
         }
     }
 
@@ -564,7 +665,11 @@
     public int getStreamMaxVolume(int streamType) {
         IAudioService service = getService();
         try {
-            return service.getStreamMaxVolume(streamType);
+            if (mUseMasterVolume) {
+                return service.getMasterMaxVolume();
+            } else {
+                return service.getStreamMaxVolume(streamType);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in getStreamMaxVolume", e);
             return 0;
@@ -582,7 +687,11 @@
     public int getStreamVolume(int streamType) {
         IAudioService service = getService();
         try {
-            return service.getStreamVolume(streamType);
+            if (mUseMasterVolume) {
+                return service.getMasterVolume();
+            } else {
+                return service.getStreamVolume(streamType);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in getStreamVolume", e);
             return 0;
@@ -597,7 +706,11 @@
     public int getLastAudibleStreamVolume(int streamType) {
         IAudioService service = getService();
         try {
-            return service.getLastAudibleStreamVolume(streamType);
+            if (mUseMasterVolume) {
+                return service.getLastAudibleMasterVolume();
+            } else {
+                return service.getLastAudibleStreamVolume(streamType);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in getLastAudibleStreamVolume", e);
             return 0;
@@ -640,13 +753,82 @@
     public void setStreamVolume(int streamType, int index, int flags) {
         IAudioService service = getService();
         try {
-            service.setStreamVolume(streamType, index, flags);
+            if (mUseMasterVolume) {
+                service.setMasterVolume(index, flags);
+            } else {
+                service.setStreamVolume(streamType, index, flags);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setStreamVolume", e);
         }
     }
 
     /**
+     * Returns the maximum volume index for master volume.
+     *
+     * @hide
+     */
+    public int getMasterMaxVolume() {
+        IAudioService service = getService();
+        try {
+            return service.getMasterMaxVolume();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in getMasterMaxVolume", e);
+            return 0;
+        }
+    }
+
+    /**
+     * Returns the current volume index for master volume.
+     *
+     * @return The current volume index for master volume.
+     * @hide
+     */
+    public int getMasterVolume() {
+        IAudioService service = getService();
+        try {
+            return service.getMasterVolume();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in getMasterVolume", e);
+            return 0;
+        }
+    }
+
+    /**
+     * Get last audible volume before master volume was muted.
+     *
+     * @hide
+     */
+    public int getLastAudibleMasterVolume() {
+        IAudioService service = getService();
+        try {
+            return service.getLastAudibleMasterVolume();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in getLastAudibleMasterVolume", e);
+            return 0;
+        }
+    }
+
+    /**
+     * Sets the volume index for master volume.
+     *
+     * @param index The volume index to set. See
+     *            {@link #getMasterMaxVolume(int)} for the largest valid value.
+     * @param flags One or more flags.
+     * @see #getMasterMaxVolume(int)
+     * @see #getMasterVolume(int)
+     * @hide
+     */
+    public void setMasterVolume(int index, int flags) {
+        IAudioService service = getService();
+        try {
+            service.setMasterVolume(index, flags);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in setMasterVolume", e);
+        }
+    }
+
+    /**
      * Solo or unsolo a particular stream. All other streams are muted.
      * <p>
      * The solo command is protected against client process death: if a process
@@ -717,6 +899,35 @@
     }
 
     /**
+     * set master mute state.
+     *
+     * @hide
+     */
+    public void setMasterMute(boolean state) {
+        IAudioService service = getService();
+        try {
+            service.setMasterMute(state, mICallBack);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in setMasterMute", e);
+        }
+    }
+
+    /**
+     * get master mute state.
+     *
+     * @hide
+     */
+    public boolean isMasterMute() {
+        IAudioService service = getService();
+        try {
+            return service.isMasterMute();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Dead object in isMasterMute", e);
+            return false;
+        }
+    }
+
+    /**
      * forces the stream controlled by hard volume keys
      * specifying streamType == -1 releases control to the
      * logic.
@@ -1509,7 +1720,7 @@
      * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
      * to actual listener objects.
      */
-    private HashMap<String, OnAudioFocusChangeListener> mAudioFocusIdListenerMap =
+    private final HashMap<String, OnAudioFocusChangeListener> mAudioFocusIdListenerMap =
             new HashMap<String, OnAudioFocusChangeListener>();
     /**
      * Lock to prevent concurrent changes to the list of focus listeners for this AudioManager
@@ -1524,7 +1735,7 @@
     /**
      * Handler for audio focus events coming from the audio service.
      */
-    private FocusEventHandlerDelegate mAudioFocusEventHandlerDelegate =
+    private final FocusEventHandlerDelegate mAudioFocusEventHandlerDelegate =
             new FocusEventHandlerDelegate();
 
     /**
@@ -1563,7 +1774,7 @@
         }
     }
 
-    private IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
+    private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
 
         public void dispatchAudioFocusChange(int focusChange, String id) {
             Message m = mAudioFocusEventHandlerDelegate.getHandler().obtainMessage(focusChange, id);
@@ -1649,11 +1860,46 @@
                     mAudioFocusDispatcher, getIdForAudioFocusListener(l),
                     mContext.getPackageName() /* package name */);
         } catch (RemoteException e) {
-            Log.e(TAG, "Can't call requestAudioFocus() from AudioService due to "+e);
+            Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
         }
         return status;
     }
 
+    /**
+     * @hide
+     * Used internally by telephony package to request audio focus. Will cause the focus request
+     * to be associated with the "voice communication" identifier only used in AudioService
+     * to identify this use case.
+     * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
+     *    the establishment of the call
+     * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
+     *    media applications resume after a call
+     */
+    public void requestAudioFocusForCall(int streamType, int durationHint) {
+        IAudioService service = getService();
+        try {
+            service.requestAudioFocus(streamType, durationHint, mICallBack, null,
+                    AudioService.IN_VOICE_COMM_FOCUS_ID,
+                    "system" /* dump-friendly package name */);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
+        }
+    }
+
+    /**
+     * @hide
+     * Used internally by telephony package to abandon audio focus, typically after a call or
+     * when ringing ends and the call is rejected or not answered.
+     * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
+     */
+    public void abandonAudioFocusForCall() {
+        IAudioService service = getService();
+        try {
+            service.abandonAudioFocus(null, AudioService.IN_VOICE_COMM_FOCUS_ID);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e);
+        }
+    }
 
     /**
      *  Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
@@ -1668,7 +1914,7 @@
             status = service.abandonAudioFocus(mAudioFocusDispatcher,
                     getIdForAudioFocusListener(l));
         } catch (RemoteException e) {
-            Log.e(TAG, "Can't call abandonAudioFocus() from AudioService due to "+e);
+            Log.e(TAG, "Can't call abandonAudioFocus() on AudioService due to "+e);
         }
         return status;
     }
@@ -1920,7 +2166,7 @@
      /**
       * {@hide}
       */
-     private IBinder mICallBack = new Binder();
+     private final IBinder mICallBack = new Binder();
 
     /**
      * Checks whether the phone is in silent mode, with or without vibrate.
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 855e831..5cc24c0 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -161,7 +161,7 @@
     /**
      * Lock to make sure mRecordingState updates are reflecting the actual state of the object.
      */
-    private Object mRecordingStateLock = new Object();
+    private final Object mRecordingStateLock = new Object();
     /**
      * The listener the AudioRecord notifies when the record position reaches a marker
      * or for periodic updates during the progression of the record head.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 2eafd68..eae03be 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -112,6 +112,7 @@
     // AudioHandler message.whats
     private static final int MSG_SET_DEVICE_VOLUME = 0;
     private static final int MSG_PERSIST_VOLUME = 1;
+    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
     private static final int MSG_PERSIST_RINGER_MODE = 3;
     private static final int MSG_PERSIST_VIBRATE_SETTING = 4;
     private static final int MSG_MEDIA_SERVER_DIED = 5;
@@ -136,7 +137,6 @@
     // Timeout for connection to bluetooth headset service
     private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
 
-
     /** @see AudioSystemThread */
     private AudioSystemThread mAudioSystemThread;
     /** @see AudioHandler */
@@ -151,10 +151,14 @@
     private boolean mMediaServerOk;
 
     private SoundPool mSoundPool;
-    private Object mSoundEffectsLock = new Object();
+    private final Object mSoundEffectsLock = new Object();
     private static final int NUM_SOUNDPOOL_CHANNELS = 4;
     private static final int SOUND_EFFECT_VOLUME = 1000;
 
+    // Internally master volume is a float in the 0.0 - 1.0 range,
+    // but to support integer based AudioManager API we translate it to 0 - 100
+    private static final int MAX_MASTER_VOLUME = 100;
+
     /* Sound effect file names  */
     private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
     private static final String[] SOUND_EFFECT_FILES = new String[] {
@@ -168,7 +172,7 @@
     /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
      * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
      * uses soundpool (second column) */
-    private int[][] SOUND_EFFECT_FILES_MAP = new int[][] {
+    private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] {
         {0, -1},  // FX_KEY_CLICK
         {0, -1},  // FX_FOCUS_NAVIGATION_UP
         {0, -1},  // FX_FOCUS_NAVIGATION_DOWN
@@ -181,7 +185,7 @@
     };
 
    /** @hide Maximum volume index values for audio streams */
-    private int[] MAX_STREAM_VOLUME = new int[] {
+    private final int[] MAX_STREAM_VOLUME = new int[] {
         5,  // STREAM_VOICE_CALL
         7,  // STREAM_SYSTEM
         7,  // STREAM_RING
@@ -197,7 +201,7 @@
      * of another stream: This avoids multiplying the volume settings for hidden
      * stream types that follow other stream behavior for volume settings
      * NOTE: do not create loops in aliases! */
-    private int[] STREAM_VOLUME_ALIAS = new int[] {
+    private final int[] STREAM_VOLUME_ALIAS = new int[] {
         AudioSystem.STREAM_VOICE_CALL,  // STREAM_VOICE_CALL
         AudioSystem.STREAM_SYSTEM,  // STREAM_SYSTEM
         AudioSystem.STREAM_RING,  // STREAM_RING
@@ -210,7 +214,7 @@
         AudioSystem.STREAM_MUSIC  // STREAM_TTS
     };
 
-    private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
+    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
         public void onError(int error) {
             switch (error) {
             case AudioSystem.AUDIO_STATUS_SERVER_DIED:
@@ -270,17 +274,22 @@
     private boolean mIsRinging = false;
 
     // Devices currently connected
-    private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
+    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
 
     // Forced device usage for communications
     private int mForcedUseForComm;
 
+    // True if we have master volume support
+    private final boolean mUseMasterVolume;
+
+    private final int[] mMasterVolumeRamp;
+
     // List of binder death handlers for setMode() client processes.
     // The last process to have called setMode() is at the top of the list.
-    private ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
+    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
 
     // List of clients having issued a SCO start request
-    private ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
+    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
 
     // BluetoothHeadset API to control SCO connection
     private BluetoothHeadset mBluetoothHeadset;
@@ -401,6 +410,13 @@
         TelephonyManager tmgr = (TelephonyManager)
                 context.getSystemService(Context.TELEPHONY_SERVICE);
         tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+
+        mUseMasterVolume = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_useMasterVolume);
+        restoreMasterVolume();
+
+        mMasterVolumeRamp = context.getResources().getIntArray(
+                com.android.internal.R.array.config_masterVolumeRamp);
     }
 
     private void createAudioSystemThread() {
@@ -602,6 +618,32 @@
         sendVolumeUpdate(streamType, oldIndex, index, flags);
     }
 
+    /** @see AudioManager#adjustMasterVolume(int) */
+    public void adjustMasterVolume(int direction, int flags) {
+        ensureValidDirection(direction);
+        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
+        int delta = 0;
+        for (int i = 0; i < mMasterVolumeRamp.length; i += 2) {
+            int testVolume = mMasterVolumeRamp[i];
+            int testDelta =  mMasterVolumeRamp[i + 1];
+            if (direction == AudioManager.ADJUST_RAISE) {
+                if (volume >= testVolume) {
+                    delta = testDelta;
+                } else {
+                    break;
+                }
+            } else if (direction == AudioManager.ADJUST_LOWER) {
+                if (volume - testDelta >= testVolume) {
+                    delta = -testDelta;
+                } else {
+                    break;
+                }
+            }
+        }
+//        Log.d(TAG, "adjustMasterVolume volume: " + volume + " delta: " + delta + " direction: " + direction);
+        setMasterVolume(volume + delta, flags);
+    }
+
     /** @see AudioManager#setStreamVolume(int, int, int) */
     public void setStreamVolume(int streamType, int index, int flags) {
         ensureValidStreamType(streamType);
@@ -657,6 +699,27 @@
         mContext.sendBroadcast(intent);
     }
 
+    // UI update and Broadcast Intent
+    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
+        mVolumePanel.postMasterVolumeChanged(flags);
+
+        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
+        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
+        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
+        mContext.sendBroadcast(intent);
+    }
+
+    // UI update and Broadcast Intent
+    private void sendMasterMuteUpdate(boolean muted, int flags) {
+        mVolumePanel.postMasterMuteChanged(flags);
+
+        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
+        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
+        long origCallerIdentityToken = Binder.clearCallingIdentity();
+        mContext.sendStickyBroadcast(intent);
+        Binder.restoreCallingIdentity(origCallerIdentityToken);
+    }
+
     /**
      * Sets the stream state's index, and posts a message to set system volume.
      * This will not call out to the UI. Assumes a valid stream type.
@@ -725,6 +788,19 @@
         return (mStreamStates[streamType].muteCount() != 0);
     }
 
+    /** @see AudioManager#setMasterMute(boolean, IBinder) */
+    public void setMasterMute(boolean state, IBinder cb) {
+        if (state != AudioSystem.getMasterMute()) {
+            AudioSystem.setMasterMute(state);
+            sendMasterMuteUpdate(state, AudioManager.FLAG_SHOW_UI);
+        }
+    }
+
+    /** get master mute state. */
+    public boolean isMasterMute() {
+        return AudioSystem.getMasterMute();
+    }
+
     /** @see AudioManager#getStreamVolume(int) */
     public int getStreamVolume(int streamType) {
         ensureValidStreamType(streamType);
@@ -732,12 +808,45 @@
         return (mStreamStates[streamType].getIndex(device, false  /* lastAudible */) + 5) / 10;
     }
 
+    public int getMasterVolume() {
+        if (isMasterMute()) return 0;
+        return getLastAudibleMasterVolume();
+    }
+
+    public void setMasterVolume(int volume, int flags) {
+        if (volume < 0) {
+            volume = 0;
+        } else if (volume > MAX_MASTER_VOLUME) {
+            volume = MAX_MASTER_VOLUME;
+        }
+        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
+    }
+
+    private void doSetMasterVolume(float volume, int flags) {
+        // don't allow changing master volume when muted
+        if (!AudioSystem.getMasterMute()) {
+            int oldVolume = getMasterVolume();
+            AudioSystem.setMasterVolume(volume);
+
+            int newVolume = getMasterVolume();
+            if (newVolume != oldVolume) {
+                // Post a persist master volume msg
+                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
+                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
+                sendMasterVolumeUpdate(flags, oldVolume, newVolume);
+            }
+        }
+    }
+
     /** @see AudioManager#getStreamMaxVolume(int) */
     public int getStreamMaxVolume(int streamType) {
         ensureValidStreamType(streamType);
         return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
     }
 
+    public int getMasterMaxVolume() {
+        return MAX_MASTER_VOLUME;
+    }
 
     /** Get last audible volume before stream was muted. */
     public int getLastAudibleStreamVolume(int streamType) {
@@ -746,6 +855,11 @@
         return (mStreamStates[streamType].getIndex(device, true  /* lastAudible */) + 5) / 10;
     }
 
+    /** Get last audible master volume before it was muted. */
+    public int getLastAudibleMasterVolume() {
+        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
+    }
+
     /** @see AudioManager#getRingerMode() */
     public int getRingerMode() {
         synchronized(mSettingsLock) {
@@ -816,6 +930,16 @@
         }
     }
 
+    private void restoreMasterVolume() {
+        if (mUseMasterVolume) {
+            float volume = Settings.System.getFloat(mContentResolver,
+                    Settings.System.VOLUME_MASTER, -1.0f);
+            if (volume >= 0.0f) {
+                AudioSystem.setMasterVolume(volume);
+            }
+        }
+    }
+
     /** @see AudioManager#shouldVibrate(int) */
     public boolean shouldVibrate(int vibrateType) {
 
@@ -992,8 +1116,6 @@
             if (mode != mMode) {
                 status = AudioSystem.setPhoneState(mode);
                 if (status == AudioSystem.AUDIO_STATUS_OK) {
-                    // automatically handle audio focus for mode changes
-                    handleFocusForCalls(mMode, mode, cb);
                     mMode = mode;
                 } else {
                     if (hdlr != null) {
@@ -1024,40 +1146,6 @@
         return newModeOwnerPid;
     }
 
-    /** pre-condition: oldMode != newMode */
-    private void handleFocusForCalls(int oldMode, int newMode, IBinder cb) {
-        // if ringing
-        if (newMode == AudioSystem.MODE_RINGTONE) {
-            // if not ringing silently
-            int ringVolume = AudioService.this.getStreamVolume(AudioManager.STREAM_RING);
-            if (ringVolume > 0) {
-                // request audio focus for the communication focus entry
-                requestAudioFocus(AudioManager.STREAM_RING,
-                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
-                        null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
-                        IN_VOICE_COMM_FOCUS_ID /*clientId*/,
-                        "system");
-
-            }
-        }
-        // if entering call
-        else if ((newMode == AudioSystem.MODE_IN_CALL)
-                || (newMode == AudioSystem.MODE_IN_COMMUNICATION)) {
-            // request audio focus for the communication focus entry
-            // (it's ok if focus was already requested during ringing)
-            requestAudioFocus(AudioManager.STREAM_RING,
-                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
-                    null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
-                    IN_VOICE_COMM_FOCUS_ID /*clientId*/,
-                    "system");
-        }
-        // if exiting call
-        else if (newMode == AudioSystem.MODE_NORMAL) {
-            // abandon audio focus for communication focus entry
-            abandonAudioFocus(null, IN_VOICE_COMM_FOCUS_ID);
-        }
-    }
-
     /** @see AudioManager#getMode() */
     public int getMode() {
         return mMode;
@@ -2391,6 +2479,11 @@
                     persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
                     break;
 
+                case MSG_PERSIST_MASTER_VOLUME:
+                    Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER,
+                            (float)msg.arg1 / (float)1000.0);
+                    break;
+
                 case MSG_PERSIST_RINGER_MODE:
                     // note that the value persisted is the current ringer mode, not the
                     // value of ringer mode as of the time the request was made to persist
@@ -2451,6 +2544,9 @@
                     // Restore ringer mode
                     setRingerModeInt(getRingerMode(), false);
 
+                    // Restore master volume
+                    restoreMasterVolume();
+
                     // indicate the end of reconfiguration phase to audio HAL
                     AudioSystem.setParameters("restarting=false");
                     break;
@@ -2875,6 +2971,11 @@
                     adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
                                             BluetoothProfile.A2DP);
                 }
+
+                if (mUseMasterVolume) {
+                    // Send sticky broadcast for initial master mute state
+                    sendMasterMuteUpdate(false, 0);
+                }
             } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
                 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                     // a package is being removed, not replaced
@@ -2896,9 +2997,10 @@
     //==========================================================================================
 
     /* constant to identify focus stack entry that is used to hold the focus while the phone
-     * is ringing or during a call
+     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
+     * entering and exiting calls.
      */
-    private final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
+    public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
 
     private final static Object mAudioFocusLock = new Object();
 
@@ -2980,7 +3082,7 @@
         }
     }
 
-    private Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
+    private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
 
     /**
      * Helper function:
@@ -3357,7 +3459,7 @@
      *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
      *  stack, audio focus or RC, can lead to a change in the remote control display
      */
-    private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
+    private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
 
     /**
      * Helper function:
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 3080497..d354cdb 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -318,5 +318,9 @@
     public static native int initStreamVolume(int stream, int indexMin, int indexMax);
     public static native int setStreamVolumeIndex(int stream, int index, int device);
     public static native int getStreamVolumeIndex(int stream, int device);
+    public static native int setMasterVolume(float value);
+    public static native float getMasterVolume();
+    public static native int setMasterMute(boolean mute);
+    public static native boolean getMasterMute();
     public static native int getDevicesForStream(int stream);
 }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 7b2f1b7..7d4c282 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -840,7 +840,10 @@
 
     /**
      * Stops playing the audio data.
-     *
+     * When used on an instance created in {@link #MODE_STREAM} mode, audio will stop playing
+     * after the last buffer that was written has been played. For an immediate stop, use
+     * {@link #pause()}, followed by {@link #flush()} to discard audio data that hasn't been played
+     * back yet.
      * @throws IllegalStateException
      */
     public void stop()
@@ -859,7 +862,7 @@
     /**
      * Pauses the playback of the audio data. Data that has not been played
      * back will not be discarded. Subsequent calls to {@link #play} will play
-     * this data back.
+     * this data back. See {@link #flush()} to discard this data.
      *
      * @throws IllegalStateException
      */
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 7d60c55..e94bddc 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -20,12 +20,12 @@
 import android.hardware.Camera.CameraInfo;
 
 /**
- * The CamcorderProfile class is used to retrieve the
+ * Retrieves the
  * predefined camcorder profile settings for camcorder applications.
  * These settings are read-only.
  *
- * The compressed output from a recording session with a given
- * CamcorderProfile contains two tracks: one for auido and one for video.
+ * <p>The compressed output from a recording session with a given
+ * CamcorderProfile contains two tracks: one for audio and one for video.
  *
  * <p>Each profile specifies the following set of parameters:
  * <ul>
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 925f965..9d6c9f6 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -111,7 +111,7 @@
     // there can only be one user at a time for the native functions (and
     // they cannot keep state in the native code across function calls). We
     // use sLock to serialize the accesses.
-    private static Object sLock = new Object();
+    private static final Object sLock = new Object();
 
     /**
      * Reads Exif tags from the specified JPEG file.
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 5294d36..17d8e4d 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -30,10 +30,14 @@
     void adjustVolume(int direction, int flags);
 
     void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags);
-    
+
     void adjustStreamVolume(int streamType, int direction, int flags);
-    
+
+    void adjustMasterVolume(int direction, int flags);
+
     void setStreamVolume(int streamType, int index, int flags);
+
+    void setMasterVolume(int index, int flags);
     
     void setStreamSolo(int streamType, boolean state, IBinder cb);
    	
@@ -41,12 +45,22 @@
 
     boolean isStreamMute(int streamType);
 
+    void setMasterMute(boolean state, IBinder cb);
+
+    boolean isMasterMute();
+
     int getStreamVolume(int streamType);
-    
+
+    int getMasterVolume();
+
     int getStreamMaxVolume(int streamType);
+
+    int getMasterMaxVolume();
     
     int getLastAudibleStreamVolume(int streamType);
 
+    int getLastAudibleMasterVolume();
+
     void setRingerMode(int ringerMode);
     
     int getRingerMode();
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index e275aa6..7f7e284 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -120,18 +120,18 @@
         }
     }
     
-    private static HashMap<String, MediaFileType> sFileTypeMap
+    private static final HashMap<String, MediaFileType> sFileTypeMap
             = new HashMap<String, MediaFileType>();
-    private static HashMap<String, Integer> sMimeTypeMap
+    private static final HashMap<String, Integer> sMimeTypeMap
             = new HashMap<String, Integer>();
     // maps file extension to MTP format code
-    private static HashMap<String, Integer> sFileTypeToFormatMap
+    private static final HashMap<String, Integer> sFileTypeToFormatMap
             = new HashMap<String, Integer>();
     // maps mime type to MTP format code
-    private static HashMap<String, Integer> sMimeTypeToFormatMap
+    private static final HashMap<String, Integer> sMimeTypeToFormatMap
             = new HashMap<String, Integer>();
     // maps MTP format code to mime type
-    private static HashMap<Integer, String> sFormatToMimeTypeMap
+    private static final HashMap<Integer, String> sFormatToMimeTypeMap
             = new HashMap<Integer, String>();
 
     static void addFileType(String extension, int fileType, String mimeType) {
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index a998407..7fcbffa 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -32,7 +32,9 @@
  * {@hide}
  */
 public class MediaInserter {
-    private HashMap<Uri, List<ContentValues>> mRowMap =
+    private final HashMap<Uri, List<ContentValues>> mRowMap =
+            new HashMap<Uri, List<ContentValues>>();
+    private final HashMap<Uri, List<ContentValues>> mPriorityRowMap =
             new HashMap<Uri, List<ContentValues>>();
 
     private IContentProvider mProvider;
@@ -44,26 +46,45 @@
     }
 
     public void insert(Uri tableUri, ContentValues values) throws RemoteException {
-        List<ContentValues> list = mRowMap.get(tableUri);
+        insert(tableUri, values, false);
+    }
+
+    public void insertwithPriority(Uri tableUri, ContentValues values) throws RemoteException {
+        insert(tableUri, values, true);
+    }
+
+    private void insert(Uri tableUri, ContentValues values, boolean priority) throws RemoteException {
+        HashMap<Uri, List<ContentValues>> rowmap = priority ? mPriorityRowMap : mRowMap;
+        List<ContentValues> list = rowmap.get(tableUri);
         if (list == null) {
             list = new ArrayList<ContentValues>();
-            mRowMap.put(tableUri, list);
+            rowmap.put(tableUri, list);
         }
         list.add(new ContentValues(values));
         if (list.size() >= mBufferSizePerUri) {
-            flush(tableUri);
+            flushAllPriority();
+            flush(tableUri, list);
         }
     }
 
     public void flushAll() throws RemoteException {
+        flushAllPriority();
         for (Uri tableUri : mRowMap.keySet()){
-            flush(tableUri);
+            List<ContentValues> list = mRowMap.get(tableUri);
+            flush(tableUri, list);
         }
         mRowMap.clear();
     }
 
-    private void flush(Uri tableUri) throws RemoteException {
-        List<ContentValues> list = mRowMap.get(tableUri);
+    private void flushAllPriority() throws RemoteException {
+        for (Uri tableUri : mPriorityRowMap.keySet()){
+            List<ContentValues> list = mPriorityRowMap.get(tableUri);
+            flush(tableUri, list);
+        }
+        mPriorityRowMap.clear();
+    }
+
+    private void flush(Uri tableUri, List<ContentValues> list) throws RemoteException {
         if (!list.isEmpty()) {
             ContentValues[] valuesArray = new ContentValues[list.size()];
             valuesArray = list.toArray(valuesArray);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 08e6032..85d99c1 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -138,10 +138,13 @@
      */
     public final class AudioSource {
       /* Do not change these values without updating their counterparts
-       * in include/media/mediarecorder.h!
+       * in system/core/include/system/audio.h!
        */
         private AudioSource() {}
+
+        /** Default audio source **/
         public static final int DEFAULT = 0;
+
         /** Microphone audio source */
         public static final int MIC = 1;
 
@@ -201,18 +204,24 @@
         /** MPEG4 media file format*/
         public static final int MPEG_4 = 2;
 
-        /** The following formats are audio only .aac or .amr formats **/
-        /** @deprecated  Deprecated in favor of AMR_NB */
-        /** Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB */
-        /** AMR NB file format */
+        /** The following formats are audio only .aac or .amr formats */
+
+        /**
+         * AMR NB file format
+         * @deprecated  Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB
+         */
         public static final int RAW_AMR = 3;
+
         /** AMR NB file format */
         public static final int AMR_NB = 3;
+
         /** AMR WB file format */
         public static final int AMR_WB = 4;
+
         /** @hide AAC ADIF file format */
         public static final int AAC_ADIF = 5;
-        /** @hide AAC ADTS file format */
+
+        /** AAC ADTS file format */
         public static final int AAC_ADTS = 6;
 
         /** @hide Stream over a socket, limited to a single stream */
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index b06ef95..52d31c7 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -35,6 +35,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.provider.MediaStore;
+import android.provider.MediaStore.Files.FileColumns;
 import android.provider.Settings;
 import android.provider.MediaStore.Audio;
 import android.provider.MediaStore.Files;
@@ -58,6 +59,8 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Locale;
 
 /**
  * Internal service helper that no-one should use directly.
@@ -312,10 +315,8 @@
 
     private final String mExternalStoragePath;
 
-    // WARNING: Bulk inserts sounded like a great idea and gave us a good performance improvement,
-    // but unfortunately it also introduced a number of bugs. All the known bugs were fixed,
-    // but we need more testing before enabling.
-    private static final boolean ENABLE_BULK_INSERTS = false;
+    /** whether to use bulk inserts or individual inserts for each item */
+    private static final boolean ENABLE_BULK_INSERTS = true;
 
     // used when scanning the image database so we know whether we have to prune
     // old thumbnail files
@@ -345,7 +346,7 @@
     // this should be set when scanning files on a case insensitive file system.
     private boolean mCaseInsensitivePaths;
 
-    private BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
+    private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
 
     private static class FileCacheEntry {
         long mRowId;
@@ -374,7 +375,7 @@
 
     // hashes file path to FileCacheEntry.
     // path should be lower case if mCaseInsensitivePaths is true
-    private HashMap<String, FileCacheEntry> mFileCache;
+    private LinkedHashMap<String, FileCacheEntry> mFileCache;
 
     private ArrayList<FileCacheEntry> mPlayLists;
 
@@ -401,7 +402,7 @@
                 + Settings.System.ALARM_ALERT);
     }
 
-    private MyMediaScannerClient mClient = new MyMediaScannerClient();
+    private final MyMediaScannerClient mClient = new MyMediaScannerClient();
 
     private boolean isDrmEnabled() {
         String prop = SystemProperties.get("drm.service.enabled");
@@ -922,16 +923,15 @@
                     }
                 }
 
-                // new file, insert it
-                // We insert directories immediately to ensure they are in the database
-                // before the files they contain.
-                // Otherwise we can get duplicate directory entries in the database
-                // if one of the media FileInserters is flushed before the files table FileInserter
-                // Also, we immediately insert the file if the rowId of the inserted file is
-                // needed.
-                if (inserter == null || needToSetSettings ||
-                        entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
+                // New file, insert it.
+                // Directories need to be inserted before the files they contain, so they
+                // get priority when bulk inserting.
+                // If the rowId of the inserted file is needed, it gets inserted immediately,
+                // bypassing the bulk inserter.
+                if (inserter == null || needToSetSettings) {
                     result = mMediaProvider.insert(tableUri, values);
+                } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
+                    inserter.insertwithPriority(tableUri, values);
                 } else {
                     inserter.insert(tableUri, values);
                 }
@@ -946,6 +946,22 @@
                 // path should never change, and we want to avoid replacing mixed cased paths
                 // with squashed lower case paths
                 values.remove(MediaStore.MediaColumns.DATA);
+
+                int mediaType = 0;
+                if (!MediaScanner.isNoMediaPath(entry.mPath)) {
+                    int fileType = MediaFile.getFileTypeForMimeType(mMimeType);
+                    if (MediaFile.isAudioFileType(fileType)) {
+                        mediaType = FileColumns.MEDIA_TYPE_AUDIO;
+                    } else if (MediaFile.isVideoFileType(fileType)) {
+                        mediaType = FileColumns.MEDIA_TYPE_VIDEO;
+                    } else if (MediaFile.isImageFileType(fileType)) {
+                        mediaType = FileColumns.MEDIA_TYPE_IMAGE;
+                    } else if (MediaFile.isPlayListFileType(fileType)) {
+                        mediaType = FileColumns.MEDIA_TYPE_PLAYLIST;
+                    }
+                    values.put(FileColumns.MEDIA_TYPE, mediaType);
+                }
+
                 mMediaProvider.update(result, values, null, null);
             }
 
@@ -1013,7 +1029,7 @@
         String[] selectionArgs = null;
 
         if (mFileCache == null) {
-            mFileCache = new HashMap<String, FileCacheEntry>();
+            mFileCache = new LinkedHashMap<String, FileCacheEntry>();
         } else {
             mFileCache.clear();
         }
@@ -1035,7 +1051,7 @@
                 // First read existing files from the files table
 
                 c = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
-                        where, selectionArgs, null);
+                        where, selectionArgs, null, null);
 
                 if (c != null) {
                     mWasEmptyPriorToScan = c.getCount() == 0;
@@ -1072,7 +1088,7 @@
 
         // compute original size of images
         mOriginalCount = 0;
-        c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null);
+        c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null);
         if (c != null) {
             mOriginalCount = c.getCount();
             c.close();
@@ -1107,7 +1123,7 @@
                     new String [] { "_data" },
                     null,
                     null,
-                    null);
+                    null, null);
             Log.v(TAG, "pruneDeadThumbnailFiles... " + c);
             if (c != null && c.moveToFirst()) {
                 do {
@@ -1134,9 +1150,52 @@
         }
     }
 
+    static class MediaBulkDeleter {
+        StringBuilder whereClause = new StringBuilder();
+        ArrayList<String> whereArgs = new ArrayList<String>(100); 
+        IContentProvider mProvider;
+        Uri mBaseUri;
+
+        public MediaBulkDeleter(IContentProvider provider, Uri baseUri) {
+            mProvider = provider;
+            mBaseUri = baseUri;
+        }
+
+        public void delete(long id) throws RemoteException {
+            if (whereClause.length() != 0) {
+                whereClause.append(",");
+            }
+            whereClause.append("?");
+            whereArgs.add("" + id);
+            if (whereArgs.size() > 100) {
+                flush();
+            }
+        }
+        public void flush() throws RemoteException {
+            int size = whereArgs.size();
+            if (size > 0) {
+                String [] foo = new String [size];
+                foo = whereArgs.toArray(foo);
+                int numrows = mProvider.delete(mBaseUri, MediaStore.MediaColumns._ID + " IN (" +
+                        whereClause.toString() + ")", foo);
+                //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
+                whereClause.setLength(0);
+                whereArgs.clear();
+            }
+        }
+    }
+
     private void postscan(String[] directories) throws RemoteException {
         Iterator<FileCacheEntry> iterator = mFileCache.values().iterator();
 
+        // Tell the provider to not delete the file.
+        // If the file is truly gone the delete is unnecessary, and we want to avoid
+        // accidentally deleting files that are really there (this may happen if the
+        // filesystem is mounted and unmounted while the scanner is running).
+        Uri.Builder builder = mFilesUri.buildUpon();
+        builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
+        MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, builder.build());
+
         while (iterator.hasNext()) {
             FileCacheEntry entry = iterator.next();
             String path = entry.mPath;
@@ -1160,16 +1219,6 @@
             }
 
             if (fileMissing) {
-                // Clear the file path to prevent the _DELETE_FILE database hook
-                // in the media provider from deleting the file.
-                // If the file is truly gone the delete is unnecessary, and we want to avoid
-                // accidentally deleting files that are really there.
-                ContentValues values = new ContentValues();
-                values.put(Files.FileColumns.DATA, "");
-                values.put(Files.FileColumns.DATE_MODIFIED, 0);
-                mMediaProvider.update(ContentUris.withAppendedId(mFilesUri, entry.mRowId),
-                        values, null, null);
-
                 // do not delete missing playlists, since they may have been modified by the user.
                 // the user can delete them in the media player instead.
                 // instead, clear the path and lastModified fields in the row
@@ -1177,12 +1226,17 @@
                 int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
 
                 if (!MediaFile.isPlayListFileType(fileType)) {
-                    mMediaProvider.delete(ContentUris.withAppendedId(mFilesUri, entry.mRowId),
-                            null, null);
+                    deleter.delete(entry.mRowId);
                     iterator.remove();
+                    if (entry.mPath.toLowerCase(Locale.US).endsWith("/.nomedia")) {
+                        deleter.flush();
+                        File f = new File(path);
+                        mMediaProvider.call(MediaStore.UNHIDE_CALL, f.getParent(), null);
+                    }
                 }
             }
         }
+        deleter.flush();
 
         // handle playlists last, after we know what media files are on the storage.
         if (mProcessPlaylists) {
@@ -1472,7 +1526,7 @@
             if (bestMatch.mRowId == 0) {
                 Cursor c = mMediaProvider.query(mAudioUri, ID_PROJECTION,
                         MediaStore.Files.FileColumns.DATA + "=?",
-                        new String[] { bestMatch.mPath }, null);
+                        new String[] { bestMatch.mPath }, null, null);
                 if (c != null) {
                     if (c.moveToNext()) {
                         bestMatch.mRowId = c.getLong(0);
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index 969da39..21b6e14 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -46,7 +46,7 @@
     private IMediaScannerService mService;
     private boolean mConnected; // true if connect() has been called since last disconnect()
 
-    private IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() {
+    private final IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() {
         public void scanCompleted(String path, Uri uri) {
             MediaScannerConnectionClient client = mClient;
             if (client != null) {
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index df141c1..63b149c 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -52,7 +52,7 @@
     private RandomAccessFile mMiniThumbFile;
     private FileChannel mChannel;
     private ByteBuffer mBuffer;
-    private static Hashtable<String, MiniThumbFile> sThumbFiles =
+    private static final Hashtable<String, MiniThumbFile> sThumbFiles =
         new Hashtable<String, MiniThumbFile>();
 
     /**
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 77acfe6..18b4ee6 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -576,6 +576,7 @@
     /**
      * Cache for the metadata strings.
      * Access synchronized on mCacheLock
+     * This is re-initialized in apply() and so cannot be final.
      */
     private Bundle mMetadata = new Bundle();
 
@@ -621,7 +622,7 @@
     /**
      * The IRemoteControlClient implementation
      */
-    private IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
+    private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
 
         public void onInformationRequested(int clientGeneration, int infoFlags,
                 int artWidth, int artHeight) {
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 9c0819f..7aaf4aa 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -224,7 +224,7 @@
      * If a column (item from this list) exists in the Cursor, its value must
      * be true (value of 1) for the row to be returned.
      */
-    private List<String> mFilterColumns = new ArrayList<String>();
+    private final List<String> mFilterColumns = new ArrayList<String>();
     
     private boolean mStopPreviousRingtone = true;
     private Ringtone mPreviousRingtone;
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 19db1c0..18aa4b3 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -266,7 +266,7 @@
             Cursor c = null;
             try {
                 c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE,
-                        new String[] { path }, null);
+                        new String[] { path }, null, null);
                 if (c != null && c.getCount() > 0) {
                     Log.w(TAG, "file already exists in beginSendObject: " + path);
                     return -1;
@@ -433,7 +433,7 @@
             }
         }
 
-        return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null);
+        return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null, null);
     }
 
     private int[] getObjectList(int storageID, int format, int parent) {
@@ -699,7 +699,7 @@
         String path = null;
         String[] whereArgs = new String[] {  Integer.toString(handle) };
         try {
-            c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null);
+            c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null, null);
             if (c != null && c.moveToNext()) {
                 path = c.getString(1);
             }
@@ -752,6 +752,29 @@
             return MtpConstants.RESPONSE_GENERAL_ERROR;
         }
 
+        // check if nomedia status changed
+        if (newFile.isDirectory()) {
+            // for directories, check if renamed from something hidden to something non-hidden
+            if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) {
+                // directory was unhidden
+                try {
+                    mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "failed to unhide/rescan for " + newPath);
+                }
+            }
+        } else {
+            // for files, check if renamed from .nomedia to something else
+            if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia")
+                    && !newPath.toLowerCase(Locale.US).equals(".nomedia")) {
+                try {
+                    mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "failed to unhide/rescan for " + newPath);
+                }
+            }
+        }
+
         return MtpConstants.RESPONSE_OK;
     }
 
@@ -815,7 +838,7 @@
         Cursor c = null;
         try {
             c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
-                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
+                            ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 outStorageFormatParent[0] = c.getInt(1);
                 outStorageFormatParent[1] = c.getInt(2);
@@ -858,7 +881,7 @@
         Cursor c = null;
         try {
             c = mMediaProvider.query(mObjectsUri, PATH_SIZE_FORMAT_PROJECTION,
-                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
+                            ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 String path = c.getString(1);
                 path.getChars(0, path.length(), outFilePath, 0);
@@ -887,7 +910,7 @@
         Cursor c = null;
         try {
             c = mMediaProvider.query(mObjectsUri, PATH_SIZE_FORMAT_PROJECTION,
-                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
+                            ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 // don't convert to media path here, since we will be matching
                 // against paths in the database matching /data/media
@@ -915,6 +938,15 @@
 
             Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
             if (mMediaProvider.delete(uri, null, null) > 0) {
+                if (format != MtpConstants.FORMAT_ASSOCIATION
+                        && path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
+                    try {
+                        String parentPath = path.substring(0, path.lastIndexOf("/"));
+                        mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "failed to unhide/rescan for " + path);
+                    }
+                }
                 return MtpConstants.RESPONSE_OK;
             } else {
                 return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
@@ -933,7 +965,7 @@
         Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
         Cursor c = null;
         try {
-            c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null);
+            c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null, null);
             if (c == null) {
                 return null;
             }
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index 76c8569..dab5454 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -191,7 +191,7 @@
             // for now we are only reading properties from the "objects" table
             c = mProvider.query(mUri,
                             new String [] { Files.FileColumns._ID, column },
-                            ID_WHERE, new String[] { Integer.toString(id) }, null);
+                            ID_WHERE, new String[] { Integer.toString(id) }, null, null);
             if (c != null && c.moveToNext()) {
                 return c.getString(1);
             } else {
@@ -211,7 +211,7 @@
         try {
             c = mProvider.query(Audio.Media.getContentUri(mVolumeName),
                             new String [] { Files.FileColumns._ID, column },
-                            ID_WHERE, new String[] { Integer.toString(id) }, null);
+                            ID_WHERE, new String[] { Integer.toString(id) }, null, null);
             if (c != null && c.moveToNext()) {
                 return c.getString(1);
             } else {
@@ -232,7 +232,7 @@
             Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
             c = mProvider.query(uri,
                             new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
-                            null, null, null);
+                            null, null, null, null);
             if (c != null && c.moveToNext()) {
                 return c.getString(1);
             } else {
@@ -254,7 +254,7 @@
             // for now we are only reading properties from the "objects" table
             c = mProvider.query(mUri,
                             new String [] { Files.FileColumns._ID, column },
-                            ID_WHERE, new String[] { Integer.toString(id) }, null);
+                            ID_WHERE, new String[] { Integer.toString(id) }, null, null);
             if (c != null && c.moveToNext()) {
                 return new Long(c.getLong(1));
             }
@@ -323,7 +323,7 @@
         try {
             // don't query if not necessary
             if (depth > 0 || handle == 0xFFFFFFFF || mColumns.length > 1) {
-                c = mProvider.query(mUri, mColumns, where, whereArgs, null);
+                c = mProvider.query(mUri, mColumns, where, whereArgs, null, null);
                 if (c == null) {
                     return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
                 }
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index ee96a95..23cc0e2 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -28,7 +28,11 @@
     libcamera_client \
     libmtp \
     libusbhost \
-    libexif
+    libexif \
+    libstagefright_amrnb_common \
+
+LOCAL_STATIC_LIBRARIES := \
+    libstagefright_amrnbenc
 
 LOCAL_C_INCLUDES += \
     external/jhead \
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index e44dc7c..b17ae45 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -57,6 +57,7 @@
     libaudioflinger \
     libbinder \
     libstagefright \
+    libstagefright_foundation \
     libstagefright_omx \
     libgui \
     libvideoeditorplayer
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 0d51def..ceb87db 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -623,7 +623,7 @@
         newTrack->setVolume(leftVolume, rightVolume);
         newTrack->setLoop(0, frameCount, loop);
 
-        // From now on, AudioTrack callbacks recevieved with previous toggle value will be ignored.
+        // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
         mToggle = toggle;
         mAudioTrack = newTrack;
         mPos = 0;
@@ -840,7 +840,7 @@
 void SoundChannel::setRate(float rate)
 {
     Mutex::Autolock lock(&mLock);
-    if (mAudioTrack != 0 && mSample.get() != 0) {
+    if (mAudioTrack != NULL && mSample != 0) {
         uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
         mAudioTrack->setSampleRate(sampleRate);
         mRate = rate;
@@ -852,7 +852,8 @@
 {
     mLeftVolume = leftVolume;
     mRightVolume = rightVolume;
-    if (mAudioTrack != 0) mAudioTrack->setVolume(leftVolume, rightVolume);
+    if (mAudioTrack != NULL)
+        mAudioTrack->setVolume(leftVolume, rightVolume);
 }
 
 void SoundChannel::setVolume(float leftVolume, float rightVolume)
@@ -864,7 +865,7 @@
 void SoundChannel::setLoop(int loop)
 {
     Mutex::Autolock lock(&mLock);
-    if (mAudioTrack != 0 && mSample.get() != 0) {
+    if (mAudioTrack != NULL && mSample != 0) {
         uint32_t loopEnd = mSample->size()/mNumChannels/
             ((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
         mAudioTrack->setLoop(0, loopEnd, loop);
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 6b11c28..002b045 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -116,7 +116,7 @@
 class SoundChannel : public SoundEvent {
 public:
     enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
-    SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1),
+    SoundChannel() : mAudioTrack(NULL), mState(IDLE), mNumChannels(1),
             mPos(0), mToggle(0), mAutoPaused(false) {}
     ~SoundChannel();
     void init(SoundPool* soundPool);
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index 9f6599f..59cd9e3 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -53,8 +53,8 @@
 static lib_entry_t *getLibrary(const char *path);
 static void resetEffectEnumeration();
 static uint32_t updateNumEffects();
-static int findEffect(effect_uuid_t *type,
-               effect_uuid_t *uuid,
+static int findEffect(const effect_uuid_t *type,
+               const effect_uuid_t *uuid,
                lib_entry_t **lib,
                effect_descriptor_t **desc);
 static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
@@ -236,7 +236,7 @@
     return ret;
 }
 
-int EffectGetDescriptor(effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
+int EffectGetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
 {
     lib_entry_t *l = NULL;
     effect_descriptor_t *d = NULL;
@@ -257,7 +257,7 @@
     return ret;
 }
 
-int EffectCreate(effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
+int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
 {
     list_elem_t *e = gLibraryList;
     lib_entry_t *l = NULL;
@@ -372,7 +372,7 @@
     return ret;
 }
 
-int EffectIsNullUuid(effect_uuid_t *uuid)
+int EffectIsNullUuid(const effect_uuid_t *uuid)
 {
     if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) {
         return 0;
@@ -628,8 +628,8 @@
     return cnt;
 }
 
-int findEffect(effect_uuid_t *type,
-               effect_uuid_t *uuid,
+int findEffect(const effect_uuid_t *type,
+               const effect_uuid_t *uuid,
                lib_entry_t **lib,
                effect_descriptor_t **desc)
 {
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 108d36a..3714283 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -195,7 +195,7 @@
     return 0;
 }     /* end EffectQueryEffect */
 
-extern "C" int EffectCreate(effect_uuid_t       *uuid,
+extern "C" int EffectCreate(const effect_uuid_t *uuid,
                             int32_t             sessionId,
                             int32_t             ioId,
                             effect_handle_t  *pHandle){
@@ -471,7 +471,7 @@
 
 } /* end EffectRelease */
 
-extern "C" int EffectGetDescriptor(effect_uuid_t       *uuid,
+extern "C" int EffectGetDescriptor(const effect_uuid_t *uuid,
                                    effect_descriptor_t *pDescriptor) {
     const effect_descriptor_t *desc = NULL;
 
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 09cd5cc..358357e 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -210,7 +210,7 @@
     return 0;
 }     /* end EffectQueryEffect */
 
-extern "C" int EffectCreate(effect_uuid_t       *uuid,
+extern "C" int EffectCreate(const effect_uuid_t *uuid,
                             int32_t             sessionId,
                             int32_t             ioId,
                             effect_handle_t  *pHandle){
@@ -317,7 +317,7 @@
     return 0;
 } /* end EffectRelease */
 
-extern "C" int EffectGetDescriptor(effect_uuid_t       *uuid,
+extern "C" int EffectGetDescriptor(const effect_uuid_t *uuid,
                                    effect_descriptor_t *pDescriptor) {
     int i;
     int length = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index 77d40b6..7f7c7e1 100755
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -13,7 +13,7 @@
 LOCAL_C_INCLUDES += \
     external/webrtc/src \
     external/webrtc/src/modules/interface \
-    external/webrtc/src/modules/audio_processing/main/interface \
+    external/webrtc/src/modules/audio_processing/interface \
     system/media/audio_effects/include
 
 LOCAL_C_INCLUDES += $(call include-path-for, speex)
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index e988e06..098a1a2 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -24,8 +24,8 @@
 #include <audio_effects/effect_aec.h>
 #include <audio_effects/effect_agc.h>
 #include <audio_effects/effect_ns.h>
-#include "modules/interface/module_common_types.h"
-#include "modules/audio_processing/main/interface/audio_processing.h"
+#include <module_common_types.h>
+#include <audio_processing.h>
 #include "speex/speex_resampler.h"
 
 
@@ -220,8 +220,8 @@
 // Automatic Gain Control (AGC)
 //------------------------------------------------------------------------------
 
-static const int kAgcDefaultTargetLevel = 0;
-static const int kAgcDefaultCompGain = 90;
+static const int kAgcDefaultTargetLevel = 3;
+static const int kAgcDefaultCompGain = 9;
 static const bool kAgcDefaultLimiter = true;
 
 int  AgcInit (preproc_effect_t *effect)
@@ -1072,7 +1072,7 @@
     return sInitStatus;
 }
 
-const effect_descriptor_t *PreProc_GetDescriptor(effect_uuid_t *uuid)
+const effect_descriptor_t *PreProc_GetDescriptor(const effect_uuid_t *uuid)
 {
     size_t i;
     for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
@@ -1298,7 +1298,7 @@
                 return -EINVAL;
             }
 
-            Session_GetConfig(effect->session, (effect_config_t *)pCmdData);
+            Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
             break;
 
         case EFFECT_CMD_SET_CONFIG_REVERSE:
@@ -1568,7 +1568,7 @@
     return 0;
 }
 
-int PreProcessingLib_Create(effect_uuid_t       *uuid,
+int PreProcessingLib_Create(const effect_uuid_t *uuid,
                             int32_t             sessionId,
                             int32_t             ioId,
                             effect_handle_t  *pInterface)
@@ -1620,7 +1620,7 @@
     return Session_ReleaseEffect(fx->session, fx);
 }
 
-int PreProcessingLib_GetDescriptor(effect_uuid_t       *uuid,
+int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid,
                                    effect_descriptor_t *pDescriptor) {
 
     if (pDescriptor == NULL || uuid == NULL){
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index 5241660..35a4a61 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -140,7 +140,7 @@
     return 0;
 } /* end EffectQueryNext */
 
-extern "C" int EffectCreate(effect_uuid_t *uuid,
+extern "C" int EffectCreate(const effect_uuid_t *uuid,
                             int32_t sessionId,
                             int32_t ioId,
                             effect_handle_t *pHandle) {
@@ -195,7 +195,7 @@
     return 0;
 } /* end EffectRelease */
 
-extern "C" int EffectGetDescriptor(effect_uuid_t       *uuid,
+extern "C" int EffectGetDescriptor(const effect_uuid_t *uuid,
                                    effect_descriptor_t *pDescriptor) {
 
     if (pDescriptor == NULL || uuid == NULL){
diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c
index ebb72c1..8351712 100644
--- a/media/libeffects/testlibs/EffectReverb.c
+++ b/media/libeffects/testlibs/EffectReverb.c
@@ -111,7 +111,7 @@
     return 0;
 }
 
-int EffectCreate(effect_uuid_t *uuid,
+int EffectCreate(const effect_uuid_t *uuid,
         int32_t sessionId,
         int32_t ioId,
         effect_handle_t *pHandle) {
@@ -182,7 +182,7 @@
     return 0;
 }
 
-int EffectGetDescriptor(effect_uuid_t       *uuid,
+int EffectGetDescriptor(const effect_uuid_t *uuid,
                         effect_descriptor_t *pDescriptor) {
     int i;
     int length = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *);
diff --git a/media/libeffects/testlibs/EffectReverb.h b/media/libeffects/testlibs/EffectReverb.h
index 5137074..1fb14a7 100644
--- a/media/libeffects/testlibs/EffectReverb.h
+++ b/media/libeffects/testlibs/EffectReverb.h
@@ -303,12 +303,12 @@
 int EffectQueryNumberEffects(uint32_t *pNumEffects);
 int EffectQueryEffect(uint32_t index,
                       effect_descriptor_t *pDescriptor);
-int EffectCreate(effect_uuid_t *effectUID,
+int EffectCreate(const effect_uuid_t *effectUID,
                  int32_t sessionId,
                  int32_t ioId,
                  effect_handle_t *pHandle);
 int EffectRelease(effect_handle_t handle);
-int EffectGetDescriptor(effect_uuid_t       *uuid,
+int EffectGetDescriptor(const effect_uuid_t *uuid,
                         effect_descriptor_t *pDescriptor);
 
 static int Reverb_Process(effect_handle_t self,
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 5d70a9b..51c8b68 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -190,7 +190,7 @@
     return 0;
 }
 
-int VisualizerLib_Create(effect_uuid_t *uuid,
+int VisualizerLib_Create(const effect_uuid_t *uuid,
                          int32_t sessionId,
                          int32_t ioId,
                          effect_handle_t *pHandle) {
@@ -240,7 +240,7 @@
     return 0;
 }
 
-int VisualizerLib_GetDescriptor(effect_uuid_t       *uuid,
+int VisualizerLib_GetDescriptor(const effect_uuid_t *uuid,
                                 effect_descriptor_t *pDescriptor) {
 
     if (pDescriptor == NULL || uuid == NULL){
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 6639d06..f9f997f 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -159,7 +159,7 @@
     mCblk->buffer = (uint8_t *)mCblk + bufOffset;
 
     iEffect->asBinder()->linkToDeath(mIEffectClient);
-    ALOGV("set() %p OK effect: %s id: %d status %d enabled %d, ", this, mDescriptor.name, mId, mStatus, mEnabled);
+    ALOGV("set() %p OK effect: %s id: %d status %d enabled %d", this, mDescriptor.name, mId, mStatus, mEnabled);
 
     return mStatus;
 }
@@ -342,7 +342,7 @@
 {
     ALOGW("IEffect died");
     mStatus = NO_INIT;
-    if (mCbf) {
+    if (mCbf != NULL) {
         status_t status = DEAD_OBJECT;
         mCbf(EVENT_ERROR, mUserData, &status);
     }
@@ -363,7 +363,7 @@
             mStatus = ALREADY_EXISTS;
         }
     }
-    if (mCbf) {
+    if (mCbf != NULL) {
         mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted);
     }
 }
@@ -373,7 +373,7 @@
     ALOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
     if (mStatus == ALREADY_EXISTS) {
         mEnabled = enabled;
-        if (mCbf) {
+        if (mCbf != NULL) {
             mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled);
         }
     }
@@ -389,7 +389,7 @@
         return;
     }
 
-    if (mCbf && cmdCode == EFFECT_CMD_SET_PARAM) {
+    if (mCbf != NULL && cmdCode == EFFECT_CMD_SET_PARAM) {
         effect_param_t *cmd = (effect_param_t *)cmdData;
         cmd->status = *(int32_t *)replyData;
         mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd);
@@ -412,7 +412,8 @@
     return af->queryEffect(index, descriptor);
 }
 
-status_t AudioEffect::getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor)
+status_t AudioEffect::getEffectDescriptor(const effect_uuid_t *uuid,
+        effect_descriptor_t *descriptor) /*const*/
 {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 5b5b076..a4068ff 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -84,7 +84,7 @@
 }
 
 AudioRecord::AudioRecord(
-        int inputSource,
+        audio_source_t inputSource,
         uint32_t sampleRate,
         audio_format_t format,
         uint32_t channelMask,
@@ -119,7 +119,7 @@
 }
 
 status_t AudioRecord::set(
-        int inputSource,
+        audio_source_t inputSource,
         uint32_t sampleRate,
         audio_format_t format,
         uint32_t channelMask,
@@ -206,7 +206,7 @@
         return status;
     }
 
-    if (cbf != 0) {
+    if (cbf != NULL) {
         mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava);
     }
 
@@ -228,7 +228,7 @@
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
-    mInputSource = (uint8_t)inputSource;
+    mInputSource = inputSource;
     mFlags = flags;
     mInput = input;
     AudioSystem::acquireAudioSessionId(mSessionId);
@@ -272,9 +272,9 @@
     }
 }
 
-int AudioRecord::inputSource() const
+audio_source_t AudioRecord::inputSource() const
 {
-    return (int)mInputSource;
+    return mInputSource;
 }
 
 // -------------------------------------------------------------------------
@@ -293,7 +293,6 @@
                 return WOULD_BLOCK;
             }
         }
-        t->mLock.lock();
      }
 
     AutoMutex lock(mLock);
@@ -305,10 +304,25 @@
     if (mActive == 0) {
         mActive = 1;
 
+        pid_t tid;
+        if (t != 0) {
+            mReadyToRun = WOULD_BLOCK;
+            t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO);
+            tid = t->getTid();  // pid_t is unknown until run()
+            ALOGV("getTid=%d", tid);
+            if (tid == -1) {
+                tid = 0;
+            }
+            // thread blocks in readyToRun()
+        } else {
+            tid = 0;    // not gettid()
+        }
+
         cblk->lock.lock();
         if (!(cblk->flags & CBLK_INVALID_MSK)) {
             cblk->lock.unlock();
-            ret = mAudioRecord->start();
+            ALOGV("mAudioRecord->start(tid=%d)", tid);
+            ret = mAudioRecord->start(tid);
             cblk->lock.lock();
             if (ret == DEAD_OBJECT) {
                 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -323,7 +337,9 @@
             cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
             cblk->waitTimeMs = 0;
             if (t != 0) {
-                t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO);
+                // thread unblocks in readyToRun() and returns NO_ERROR
+                mReadyToRun = NO_ERROR;
+                mCondition.signal();
             } else {
                 mPreviousPriority = getpriority(PRIO_PROCESS, 0);
                 mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
@@ -331,13 +347,12 @@
             }
         } else {
             mActive = 0;
+            // thread unblocks in readyToRun() and returns NO_INIT
+            mReadyToRun = NO_INIT;
+            mCondition.signal();
         }
     }
 
-    if (t != 0) {
-        t->mLock.unlock();
-    }
-
     return ret;
 }
 
@@ -347,10 +362,6 @@
 
     ALOGV("stop");
 
-    if (t != 0) {
-        t->mLock.lock();
-    }
-
     AutoMutex lock(mLock);
     if (mActive == 1) {
         mActive = 0;
@@ -367,10 +378,6 @@
         }
     }
 
-    if (t != 0) {
-        t->mLock.unlock();
-    }
-
     return NO_ERROR;
 }
 
@@ -387,7 +394,7 @@
 
 status_t AudioRecord::setMarkerPosition(uint32_t marker)
 {
-    if (mCbf == 0) return INVALID_OPERATION;
+    if (mCbf == NULL) return INVALID_OPERATION;
 
     mMarkerPosition = marker;
     mMarkerReached = false;
@@ -397,7 +404,7 @@
 
 status_t AudioRecord::getMarkerPosition(uint32_t *marker)
 {
-    if (marker == 0) return BAD_VALUE;
+    if (marker == NULL) return BAD_VALUE;
 
     *marker = mMarkerPosition;
 
@@ -406,7 +413,7 @@
 
 status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
 {
-    if (mCbf == 0) return INVALID_OPERATION;
+    if (mCbf == NULL) return INVALID_OPERATION;
 
     uint32_t curPosition;
     getPosition(&curPosition);
@@ -418,7 +425,7 @@
 
 status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod)
 {
-    if (updatePeriod == 0) return BAD_VALUE;
+    if (updatePeriod == NULL) return BAD_VALUE;
 
     *updatePeriod = mUpdatePeriod;
 
@@ -427,7 +434,7 @@
 
 status_t AudioRecord::getPosition(uint32_t *position)
 {
-    if (position == 0) return BAD_VALUE;
+    if (position == NULL) return BAD_VALUE;
 
     AutoMutex lock(mLock);
     *position = mCblk->user;
@@ -535,7 +542,7 @@
                     ALOGW(   "obtainBuffer timed out (is the CPU pegged?) "
                             "user=%08x, server=%08x", cblk->user, cblk->server);
                     cblk->lock.unlock();
-                    result = mAudioRecord->start();
+                    result = mAudioRecord->start(0);    // callback thread hasn't changed
                     cblk->lock.lock();
                     if (result == DEAD_OBJECT) {
                         android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -773,7 +780,7 @@
         result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask,
                 mFrameCount, mFlags, getInput_l());
         if (result == NO_ERROR) {
-            result = mAudioRecord->start();
+            result = mAudioRecord->start(0);    // callback thread hasn't changed
         }
         if (result != NO_ERROR) {
             mActive = false;
@@ -824,6 +831,15 @@
     return mReceiver.processAudioBuffer(this);
 }
 
+status_t AudioRecord::ClientRecordThread::readyToRun()
+{
+    AutoMutex(mReceiver.mLock);
+    while (mReceiver.mReadyToRun == WOULD_BLOCK) {
+        mReceiver.mCondition.wait(mReceiver.mLock);
+    }
+    return mReceiver.mReadyToRun;
+}
+
 // -------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 952d634..ec4c044 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -35,7 +35,8 @@
 sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
 audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
 // Cached values
-DefaultKeyedVector<int, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
+
+DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
 DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
 
 // Cached values for recording queries, all protected by gLock
@@ -120,7 +121,8 @@
     return NO_ERROR;
 }
 
-status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value, int output)
+status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,
+        audio_io_handle_t output)
 {
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
@@ -138,7 +140,8 @@
     return NO_ERROR;
 }
 
-status_t AudioSystem::getStreamVolume(audio_stream_type_t stream, float* volume, int output)
+status_t AudioSystem::getStreamVolume(audio_stream_type_t stream, float* volume,
+        audio_io_handle_t output)
 {
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
@@ -224,7 +227,7 @@
 
     gLock.lock();
     outputDesc = AudioSystem::gOutputs.valueFor(output);
-    if (outputDesc == 0) {
+    if (outputDesc == NULL) {
         ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output);
         gLock.unlock();
         const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
@@ -262,7 +265,7 @@
 
     gLock.lock();
     outputDesc = AudioSystem::gOutputs.valueFor(output);
-    if (outputDesc == 0) {
+    if (outputDesc == NULL) {
         gLock.unlock();
         const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
         if (af == 0) return PERMISSION_DENIED;
@@ -293,7 +296,7 @@
 
     gLock.lock();
     outputDesc = AudioSystem::gOutputs.valueFor(output);
-    if (outputDesc == 0) {
+    if (outputDesc == NULL) {
         gLock.unlock();
         const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
         if (af == 0) return PERMISSION_DENIED;
@@ -401,10 +404,11 @@
     ALOGW("AudioFlinger server died!");
 }
 
-void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) {
+void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle_t ioHandle,
+        void *param2) {
     ALOGV("ioConfigChanged() event %d", event);
     OutputDescriptor *desc;
-    uint32_t stream;
+    audio_stream_type_t stream;
 
     if (ioHandle == 0) return;
 
@@ -412,8 +416,8 @@
 
     switch (event) {
     case STREAM_CONFIG_CHANGED:
-        if (param2 == 0) break;
-        stream = *(uint32_t *)param2;
+        if (param2 == NULL) break;
+        stream = *(audio_stream_type_t *)param2;
         ALOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle);
         if (gStreamOutputMap.indexOfKey(stream) >= 0) {
             gStreamOutputMap.replaceValueFor(stream, ioHandle);
@@ -424,7 +428,7 @@
             ALOGV("ioConfigChanged() opening already existing output! %d", ioHandle);
             break;
         }
-        if (param2 == 0) break;
+        if (param2 == NULL) break;
         desc = (OutputDescriptor *)param2;
 
         OutputDescriptor *outputDesc =  new OutputDescriptor(*desc);
@@ -453,7 +457,7 @@
             ALOGW("ioConfigChanged() modifying unknow output! %d", ioHandle);
             break;
         }
-        if (param2 == 0) break;
+        if (param2 == NULL) break;
         desc = (OutputDescriptor *)param2;
 
         ALOGV("ioConfigChanged() new config for output %d samplingRate %d, format %d channels %d frameCount %d latency %d",
@@ -630,7 +634,7 @@
     aps->releaseOutput(output);
 }
 
-audio_io_handle_t AudioSystem::getInput(int inputSource,
+audio_io_handle_t AudioSystem::getInput(audio_source_t inputSource,
                                     uint32_t samplingRate,
                                     audio_format_t format,
                                     uint32_t channels,
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 17e3d4b..aead9a1 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1,4 +1,4 @@
-/* frameworks/base/media/libmedia/AudioTrack.cpp
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
@@ -257,7 +257,7 @@
         return status;
     }
 
-    if (cbf != 0) {
+    if (cbf != NULL) {
         mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
     }
 
@@ -345,7 +345,6 @@
                 return;
             }
         }
-        t->mLock.lock();
      }
 
     AutoMutex lock(mLock);
@@ -363,18 +362,26 @@
         cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
         cblk->waitTimeMs = 0;
         android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
+        pid_t tid;
         if (t != 0) {
             t->run("AudioTrackThread", ANDROID_PRIORITY_AUDIO);
+            tid = t->getTid();  // pid_t is unknown until run()
+            ALOGV("getTid=%d", tid);
+            if (tid == -1) {
+                tid = 0;
+            }
         } else {
             mPreviousPriority = getpriority(PRIO_PROCESS, 0);
             mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
             androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
+            tid = 0;    // not gettid()
         }
 
         ALOGV("start %p before lock cblk %p", this, mCblk);
         if (!(cblk->flags & CBLK_INVALID_MSK)) {
             cblk->lock.unlock();
-            status = mAudioTrack->start();
+            ALOGV("mAudioTrack->start(tid=%d)", tid);
+            status = mAudioTrack->start(tid);
             cblk->lock.lock();
             if (status == DEAD_OBJECT) {
                 android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -396,9 +403,6 @@
         }
     }
 
-    if (t != 0) {
-        t->mLock.unlock();
-    }
 }
 
 void AudioTrack::stop()
@@ -406,9 +410,6 @@
     sp<AudioTrackThread> t = mAudioTrackThread;
 
     ALOGV("stop %p", this);
-    if (t != 0) {
-        t->mLock.lock();
-    }
 
     AutoMutex lock(mLock);
     if (mActive) {
@@ -434,9 +435,6 @@
         }
     }
 
-    if (t != 0) {
-        t->mLock.unlock();
-    }
 }
 
 bool AudioTrack::stopped() const
@@ -501,12 +499,12 @@
     mVolume[LEFT] = left;
     mVolume[RIGHT] = right;
 
-    mCblk->volumeLR = (uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000);
+    mCblk->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
 
     return NO_ERROR;
 }
 
-void AudioTrack::getVolume(float* left, float* right)
+void AudioTrack::getVolume(float* left, float* right) const
 {
     if (left != NULL) {
         *left  = mVolume[LEFT];
@@ -531,7 +529,7 @@
     return NO_ERROR;
 }
 
-void AudioTrack::getAuxEffectSendLevel(float* level)
+void AudioTrack::getAuxEffectSendLevel(float* level) const
 {
     if (level != NULL) {
         *level  = mSendLevel;
@@ -553,7 +551,7 @@
     return NO_ERROR;
 }
 
-uint32_t AudioTrack::getSampleRate()
+uint32_t AudioTrack::getSampleRate() const
 {
     AutoMutex lock(mLock);
     return mCblk->sampleRate;
@@ -601,29 +599,9 @@
     return NO_ERROR;
 }
 
-status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
-{
-    AutoMutex lock(mLock);
-    if (loopStart != 0) {
-        *loopStart = mCblk->loopStart;
-    }
-    if (loopEnd != 0) {
-        *loopEnd = mCblk->loopEnd;
-    }
-    if (loopCount != 0) {
-        if (mCblk->loopCount < 0) {
-            *loopCount = -1;
-        } else {
-            *loopCount = mCblk->loopCount;
-        }
-    }
-
-    return NO_ERROR;
-}
-
 status_t AudioTrack::setMarkerPosition(uint32_t marker)
 {
-    if (mCbf == 0) return INVALID_OPERATION;
+    if (mCbf == NULL) return INVALID_OPERATION;
 
     mMarkerPosition = marker;
     mMarkerReached = false;
@@ -631,9 +609,9 @@
     return NO_ERROR;
 }
 
-status_t AudioTrack::getMarkerPosition(uint32_t *marker)
+status_t AudioTrack::getMarkerPosition(uint32_t *marker) const
 {
-    if (marker == 0) return BAD_VALUE;
+    if (marker == NULL) return BAD_VALUE;
 
     *marker = mMarkerPosition;
 
@@ -642,7 +620,7 @@
 
 status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
 {
-    if (mCbf == 0) return INVALID_OPERATION;
+    if (mCbf == NULL) return INVALID_OPERATION;
 
     uint32_t curPosition;
     getPosition(&curPosition);
@@ -652,9 +630,9 @@
     return NO_ERROR;
 }
 
-status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod)
+status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const
 {
-    if (updatePeriod == 0) return BAD_VALUE;
+    if (updatePeriod == NULL) return BAD_VALUE;
 
     *updatePeriod = mUpdatePeriod;
 
@@ -679,7 +657,7 @@
 
 status_t AudioTrack::getPosition(uint32_t *position)
 {
-    if (position == 0) return BAD_VALUE;
+    if (position == NULL) return BAD_VALUE;
     AutoMutex lock(mLock);
     *position = mFlushed ? 0 : mCblk->server;
 
@@ -712,7 +690,7 @@
             mCblk->sampleRate, mFormat, mChannelMask, (audio_policy_output_flags_t)mFlags);
 }
 
-int AudioTrack::getSessionId()
+int AudioTrack::getSessionId() const
 {
     return mSessionId;
 }
@@ -794,7 +772,7 @@
                 }
             }
         } else {
-            // Ensure that buffer alignment matches channelcount
+            // Ensure that buffer alignment matches channelCount
             int channelCount = popcount(channelMask);
             if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
                 ALOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
@@ -837,7 +815,7 @@
         mCblk->stepUser(mCblk->frameCount);
     }
 
-    mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000);
+    mCblk->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000));
     mCblk->setSendLevel(mSendLevel);
     mAudioTrack->attachAuxEffect(mAuxEffectId);
     mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
@@ -905,7 +883,7 @@
                                 "user=%08x, server=%08x", this, cblk->user, cblk->server);
                         //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
                         cblk->lock.unlock();
-                        result = mAudioTrack->start();
+                        result = mAudioTrack->start(0); // callback thread hasn't changed
                         cblk->lock.lock();
                         if (result == DEAD_OBJECT) {
                             android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -937,7 +915,7 @@
     if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
         android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
         ALOGW("obtainBuffer() track %p disabled, restarting", this);
-        mAudioTrack->start();
+        mAudioTrack->start(0);  // callback thread hasn't changed
     }
 
     cblk->waitTimeMs = 0;
@@ -981,7 +959,8 @@
     if (mSharedBuffer != 0) return INVALID_OPERATION;
 
     if (ssize_t(userSize) < 0) {
-        // sanity-check. user is most-likely passing an error code.
+        // Sanity-check: user is most-likely passing an error code, and it would
+        // make the return value ambiguous (actualSize vs error).
         ALOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
                 buffer, userSize, userSize);
         return BAD_VALUE;
@@ -1004,8 +983,6 @@
     do {
         audioBuffer.frameCount = userSize/frameSz;
 
-        // Calling obtainBuffer() with a negative wait count causes
-        // an (almost) infinite wait time.
         status_t err = obtainBuffer(&audioBuffer, -1);
         if (err < 0) {
             // out of buffers, return #bytes written
@@ -1095,6 +1072,9 @@
         frames = mRemainingFrames;
     }
 
+    // See description of waitCount parameter at declaration of obtainBuffer().
+    // The logic below prevents us from being stuck below at obtainBuffer()
+    // not being able to handle timed events (position, markers, loops).
     int32_t waitCount = -1;
     if (mUpdatePeriod || (!mMarkerReached && mMarkerPosition) || mLoopCount) {
         waitCount = 1;
@@ -1104,9 +1084,6 @@
 
         audioBuffer.frameCount = frames;
 
-        // Calling obtainBuffer() with a wait count of 1
-        // limits wait time to WAIT_PERIOD_MS. This prevents from being
-        // stuck here not being able to handle timed events (position, markers, loops).
         status_t err = obtainBuffer(&audioBuffer, waitCount);
         if (err < NO_ERROR) {
             if (err != TIMED_OUT) {
@@ -1228,7 +1205,7 @@
                 }
             }
             if (mActive) {
-                result = mAudioTrack->start();
+                result = mAudioTrack->start(0); // callback thread hasn't changed
                 ALOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result);
             }
             if (fromStart && result == NO_ERROR) {
@@ -1319,8 +1296,8 @@
 
 audio_track_cblk_t::audio_track_cblk_t()
     : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
-    userBase(0), serverBase(0), buffers(0), frameCount(0),
-    loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),
+    userBase(0), serverBase(0), buffers(NULL), frameCount(0),
+    loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000),
     mSendLevel(0), flags(0)
 {
 }
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 0d442ef..4507e5d 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -89,7 +89,7 @@
                                 int frameCount,
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
-                                int output,
+                                audio_io_handle_t output,
                                 int *sessionId,
                                 status_t *status)
     {
@@ -104,7 +104,7 @@
         data.writeInt32(frameCount);
         data.writeInt32(flags);
         data.writeStrongBinder(sharedBuffer->asBinder());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         int lSessionId = 0;
         if (sessionId != NULL) {
             lSessionId = *sessionId;
@@ -129,7 +129,7 @@
 
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
-                                int input,
+                                audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 uint32_t channelMask,
@@ -142,7 +142,7 @@
         sp<IAudioRecord> record;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(pid);
-        data.writeInt32(input);
+        data.writeInt32((int32_t) input);
         data.writeInt32(sampleRate);
         data.writeInt32(format);
         data.writeInt32(channelMask);
@@ -170,47 +170,47 @@
         return record;
     }
 
-    virtual uint32_t sampleRate(int output) const
+    virtual uint32_t sampleRate(audio_io_handle_t output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(SAMPLE_RATE, data, &reply);
         return reply.readInt32();
     }
 
-    virtual int channelCount(int output) const
+    virtual int channelCount(audio_io_handle_t output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(CHANNEL_COUNT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual audio_format_t format(int output) const
+    virtual audio_format_t format(audio_io_handle_t output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(FORMAT, data, &reply);
         return (audio_format_t) reply.readInt32();
     }
 
-    virtual size_t frameCount(int output) const
+    virtual size_t frameCount(audio_io_handle_t output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(FRAME_COUNT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual uint32_t latency(int output) const
+    virtual uint32_t latency(audio_io_handle_t output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(LATENCY, data, &reply);
         return reply.readInt32();
     }
@@ -249,13 +249,14 @@
         return reply.readInt32();
     }
 
-    virtual status_t setStreamVolume(audio_stream_type_t stream, float value, int output)
+    virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
+            audio_io_handle_t output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32((int32_t) stream);
         data.writeFloat(value);
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(SET_STREAM_VOLUME, data, &reply);
         return reply.readInt32();
     }
@@ -270,12 +271,12 @@
         return reply.readInt32();
     }
 
-    virtual float streamVolume(audio_stream_type_t stream, int output) const
+    virtual float streamVolume(audio_stream_type_t stream, audio_io_handle_t output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32((int32_t) stream);
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(STREAM_VOLUME, data, &reply);
         return reply.readFloat();
     }
@@ -315,21 +316,21 @@
         return reply.readInt32();
     }
 
-    virtual status_t setParameters(int ioHandle, const String8& keyValuePairs)
+    virtual status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(ioHandle);
+        data.writeInt32((int32_t) ioHandle);
         data.writeString8(keyValuePairs);
         remote()->transact(SET_PARAMETERS, data, &reply);
         return reply.readInt32();
     }
 
-    virtual String8 getParameters(int ioHandle, const String8& keys)
+    virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(ioHandle);
+        data.writeInt32((int32_t) ioHandle);
         data.writeString8(keys);
         remote()->transact(GET_PARAMETERS, data, &reply);
         return reply.readString8();
@@ -343,7 +344,7 @@
         remote()->transact(REGISTER_CLIENT, data, &reply);
     }
 
-    virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount)
+    virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -354,7 +355,7 @@
         return reply.readInt32();
     }
 
-    virtual int openOutput(uint32_t *pDevices,
+    virtual audio_io_handle_t openOutput(uint32_t *pDevices,
                             uint32_t *pSamplingRate,
                             audio_format_t *pFormat,
                             uint32_t *pChannels,
@@ -376,8 +377,8 @@
         data.writeInt32(latency);
         data.writeInt32(flags);
         remote()->transact(OPEN_OUTPUT, data, &reply);
-        int  output = reply.readInt32();
-        ALOGV("openOutput() returned output, %p", output);
+        audio_io_handle_t output = (audio_io_handle_t) reply.readInt32();
+        ALOGV("openOutput() returned output, %d", output);
         devices = reply.readInt32();
         if (pDevices) *pDevices = devices;
         samplingRate = reply.readInt32();
@@ -391,48 +392,49 @@
         return output;
     }
 
-    virtual int openDuplicateOutput(int output1, int output2)
+    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+            audio_io_handle_t output2)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output1);
-        data.writeInt32(output2);
+        data.writeInt32((int32_t) output1);
+        data.writeInt32((int32_t) output2);
         remote()->transact(OPEN_DUPLICATE_OUTPUT, data, &reply);
-        return reply.readInt32();
+        return (audio_io_handle_t) reply.readInt32();
     }
 
-    virtual status_t closeOutput(int output)
+    virtual status_t closeOutput(audio_io_handle_t output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(CLOSE_OUTPUT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual status_t suspendOutput(int output)
+    virtual status_t suspendOutput(audio_io_handle_t output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(SUSPEND_OUTPUT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual status_t restoreOutput(int output)
+    virtual status_t restoreOutput(audio_io_handle_t output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(RESTORE_OUTPUT, data, &reply);
         return reply.readInt32();
     }
 
-    virtual int openInput(uint32_t *pDevices,
+    virtual audio_io_handle_t openInput(uint32_t *pDevices,
                             uint32_t *pSamplingRate,
                             audio_format_t *pFormat,
                             uint32_t *pChannels,
-                            uint32_t acoustics)
+                            audio_in_acoustics_t acoustics)
     {
         Parcel data, reply;
         uint32_t devices = pDevices ? *pDevices : 0;
@@ -445,9 +447,9 @@
         data.writeInt32(samplingRate);
         data.writeInt32(format);
         data.writeInt32(channels);
-        data.writeInt32(acoustics);
+        data.writeInt32((int32_t) acoustics);
         remote()->transact(OPEN_INPUT, data, &reply);
-        int input = reply.readInt32();
+        audio_io_handle_t input = (audio_io_handle_t) reply.readInt32();
         devices = reply.readInt32();
         if (pDevices) *pDevices = devices;
         samplingRate = reply.readInt32();
@@ -468,12 +470,12 @@
         return reply.readInt32();
     }
 
-    virtual status_t setStreamOutput(audio_stream_type_t stream, int output)
+    virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32((int32_t) stream);
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(SET_STREAM_OUTPUT, data, &reply);
         return reply.readInt32();
     }
@@ -487,11 +489,12 @@
         return reply.readInt32();
     }
 
-    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output)
+    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
+            audio_io_handle_t output) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         remote()->transact(GET_RENDER_POSITION, data, &reply);
         status_t status = reply.readInt32();
         if (status == NO_ERROR) {
@@ -507,11 +510,11 @@
         return status;
     }
 
-    virtual unsigned int getInputFramesLost(int ioHandle)
+    virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(ioHandle);
+        data.writeInt32((int32_t) ioHandle);
         remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
         return reply.readInt32();
     }
@@ -544,7 +547,7 @@
         remote()->transact(RELEASE_AUDIO_SESSION_ID, data, &reply);
     }
 
-    virtual status_t queryNumberEffects(uint32_t *numEffects)
+    virtual status_t queryNumberEffects(uint32_t *numEffects) const
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -556,13 +559,13 @@
         if (status != NO_ERROR) {
             return status;
         }
-        if (numEffects) {
+        if (numEffects != NULL) {
             *numEffects = (uint32_t)reply.readInt32();
         }
         return NO_ERROR;
     }
 
-    virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
+    virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) const
     {
         if (pDescriptor == NULL) {
             return BAD_VALUE;
@@ -582,7 +585,8 @@
         return NO_ERROR;
     }
 
-    virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *pDescriptor)
+    virtual status_t getEffectDescriptor(const effect_uuid_t *pUuid,
+            effect_descriptor_t *pDescriptor) const
     {
         if (pUuid == NULL || pDescriptor == NULL) {
             return BAD_VALUE;
@@ -606,7 +610,7 @@
                                     effect_descriptor_t *pDesc,
                                     const sp<IEffectClient>& client,
                                     int32_t priority,
-                                    int output,
+                                    audio_io_handle_t output,
                                     int sessionId,
                                     status_t *status,
                                     int *id,
@@ -627,7 +631,7 @@
         data.write(pDesc, sizeof(effect_descriptor_t));
         data.writeStrongBinder(client->asBinder());
         data.writeInt32(priority);
-        data.writeInt32(output);
+        data.writeInt32((int32_t) output);
         data.writeInt32(sessionId);
 
         status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply);
@@ -640,7 +644,7 @@
                 *id = tmp;
             }
             tmp = reply.readInt32();
-            if (enabled) {
+            if (enabled != NULL) {
                 *enabled = tmp;
             }
             effect = interface_cast<IEffect>(reply.readStrongBinder());
@@ -653,13 +657,14 @@
         return effect;
     }
 
-    virtual status_t moveEffects(int session, int srcOutput, int dstOutput)
+    virtual status_t moveEffects(int session, audio_io_handle_t srcOutput,
+            audio_io_handle_t dstOutput)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(session);
-        data.writeInt32(srcOutput);
-        data.writeInt32(dstOutput);
+        data.writeInt32((int32_t) srcOutput);
+        data.writeInt32((int32_t) dstOutput);
         remote()->transact(MOVE_EFFECTS, data, &reply);
         return reply.readInt32();
     }
@@ -683,7 +688,7 @@
             size_t bufferCount = data.readInt32();
             uint32_t flags = data.readInt32();
             sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
-            int output = data.readInt32();
+            audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
             int sessionId = data.readInt32();
             status_t status;
             sp<IAudioTrack> track = createTrack(pid,
@@ -697,7 +702,7 @@
         case OPEN_RECORD: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             pid_t pid = data.readInt32();
-            int input = data.readInt32();
+            audio_io_handle_t input = (audio_io_handle_t) data.readInt32();
             uint32_t sampleRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
             int channelCount = data.readInt32();
@@ -714,27 +719,27 @@
         } break;
         case SAMPLE_RATE: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( sampleRate(data.readInt32()) );
+            reply->writeInt32( sampleRate((audio_io_handle_t) data.readInt32()) );
             return NO_ERROR;
         } break;
         case CHANNEL_COUNT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( channelCount(data.readInt32()) );
+            reply->writeInt32( channelCount((audio_io_handle_t) data.readInt32()) );
             return NO_ERROR;
         } break;
         case FORMAT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( format(data.readInt32()) );
+            reply->writeInt32( format((audio_io_handle_t) data.readInt32()) );
             return NO_ERROR;
         } break;
         case FRAME_COUNT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( frameCount(data.readInt32()) );
+            reply->writeInt32( frameCount((audio_io_handle_t) data.readInt32()) );
             return NO_ERROR;
         } break;
         case LATENCY: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32( latency(data.readInt32()) );
+            reply->writeInt32( latency((audio_io_handle_t) data.readInt32()) );
             return NO_ERROR;
         } break;
          case SET_MASTER_VOLUME: {
@@ -761,7 +766,7 @@
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int stream = data.readInt32();
             float volume = data.readFloat();
-            int output = data.readInt32();
+            audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
             reply->writeInt32( setStreamVolume((audio_stream_type_t) stream, volume, output) );
             return NO_ERROR;
         } break;
@@ -803,14 +808,14 @@
         } break;
         case SET_PARAMETERS: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int ioHandle = data.readInt32();
+            audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
             String8 keyValuePairs(data.readString8());
             reply->writeInt32(setParameters(ioHandle, keyValuePairs));
             return NO_ERROR;
          } break;
         case GET_PARAMETERS: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int ioHandle = data.readInt32();
+            audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
             String8 keys(data.readString8());
             reply->writeString8(getParameters(ioHandle, keys));
             return NO_ERROR;
@@ -838,14 +843,14 @@
             uint32_t channels = data.readInt32();
             uint32_t latency = data.readInt32();
             uint32_t flags = data.readInt32();
-            int output = openOutput(&devices,
+            audio_io_handle_t output = openOutput(&devices,
                                      &samplingRate,
                                      &format,
                                      &channels,
                                      &latency,
                                      flags);
             ALOGV("OPEN_OUTPUT output, %p", output);
-            reply->writeInt32(output);
+            reply->writeInt32((int32_t) output);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
             reply->writeInt32(format);
@@ -855,24 +860,24 @@
         } break;
         case OPEN_DUPLICATE_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int output1 = data.readInt32();
-            int output2 = data.readInt32();
-            reply->writeInt32(openDuplicateOutput(output1, output2));
+            audio_io_handle_t output1 = (audio_io_handle_t) data.readInt32();
+            audio_io_handle_t output2 = (audio_io_handle_t) data.readInt32();
+            reply->writeInt32((int32_t) openDuplicateOutput(output1, output2));
             return NO_ERROR;
         } break;
         case CLOSE_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32(closeOutput(data.readInt32()));
+            reply->writeInt32(closeOutput((audio_io_handle_t) data.readInt32()));
             return NO_ERROR;
         } break;
         case SUSPEND_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32(suspendOutput(data.readInt32()));
+            reply->writeInt32(suspendOutput((audio_io_handle_t) data.readInt32()));
             return NO_ERROR;
         } break;
         case RESTORE_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32(restoreOutput(data.readInt32()));
+            reply->writeInt32(restoreOutput((audio_io_handle_t) data.readInt32()));
             return NO_ERROR;
         } break;
         case OPEN_INPUT: {
@@ -881,14 +886,14 @@
             uint32_t samplingRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
             uint32_t channels = data.readInt32();
-            uint32_t acoutics = data.readInt32();
+            audio_in_acoustics_t acoustics = (audio_in_acoustics_t) data.readInt32();
 
-            int input = openInput(&devices,
+            audio_io_handle_t input = openInput(&devices,
                                      &samplingRate,
                                      &format,
                                      &channels,
-                                     acoutics);
-            reply->writeInt32(input);
+                                     acoustics);
+            reply->writeInt32((int32_t) input);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
             reply->writeInt32(format);
@@ -897,13 +902,13 @@
         } break;
         case CLOSE_INPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            reply->writeInt32(closeInput(data.readInt32()));
+            reply->writeInt32(closeInput((audio_io_handle_t) data.readInt32()));
             return NO_ERROR;
         } break;
         case SET_STREAM_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             uint32_t stream = data.readInt32();
-            int output = data.readInt32();
+            audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
             reply->writeInt32(setStreamOutput((audio_stream_type_t) stream, output));
             return NO_ERROR;
         } break;
@@ -915,7 +920,7 @@
         } break;
         case GET_RENDER_POSITION: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int output = data.readInt32();
+            audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
             uint32_t halFrames;
             uint32_t dspFrames;
             status_t status = getRenderPosition(&halFrames, &dspFrames, output);
@@ -928,7 +933,7 @@
         }
         case GET_INPUT_FRAMES_LOST: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            int ioHandle = data.readInt32();
+            audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
             reply->writeInt32(getInputFramesLost(ioHandle));
             return NO_ERROR;
         } break;
@@ -988,7 +993,7 @@
             data.read(&desc, sizeof(effect_descriptor_t));
             sp<IEffectClient> client = interface_cast<IEffectClient>(data.readStrongBinder());
             int32_t priority = data.readInt32();
-            int output = data.readInt32();
+            audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
             int sessionId = data.readInt32();
             status_t status;
             int id;
@@ -1005,8 +1010,8 @@
         case MOVE_EFFECTS: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int session = data.readInt32();
-            int srcOutput = data.readInt32();
-            int dstOutput = data.readInt32();
+            audio_io_handle_t srcOutput = (audio_io_handle_t) data.readInt32();
+            audio_io_handle_t dstOutput = (audio_io_handle_t) data.readInt32();
             reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index 5a3f250..ce28b33 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -39,12 +39,12 @@
     {
     }
 
-    void ioConfigChanged(int event, int ioHandle, void *param2)
+    void ioConfigChanged(int event, audio_io_handle_t ioHandle, void *param2)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
         data.writeInt32(event);
-        data.writeInt32(ioHandle);
+        data.writeInt32((int32_t) ioHandle);
         if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
             uint32_t stream = *(uint32_t *)param2;
             ALOGV("ioConfigChanged stream %d", stream);
@@ -72,8 +72,8 @@
     case IO_CONFIG_CHANGED: {
             CHECK_INTERFACE(IAudioFlingerClient, data, reply);
             int event = data.readInt32();
-            int ioHandle = data.readInt32();
-            void *param2 = 0;
+            audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
+            void *param2 = NULL;
             AudioSystem::OutputDescriptor desc;
             uint32_t stream;
             if (event == AudioSystem::STREAM_CONFIG_CHANGED) {
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index b5c857f..99385aa4 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -172,7 +172,7 @@
     }
 
     virtual audio_io_handle_t getInput(
-                                    int inputSource,
+                                    audio_source_t inputSource,
                                     uint32_t samplingRate,
                                     audio_format_t format,
                                     uint32_t channels,
@@ -181,7 +181,7 @@
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
-        data.writeInt32(inputSource);
+        data.writeInt32((int32_t) inputSource);
         data.writeInt32(samplingRate);
         data.writeInt32(static_cast <uint32_t>(format));
         data.writeInt32(channels);
@@ -461,7 +461,7 @@
 
         case GET_INPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
-            int inputSource = data.readInt32();
+            audio_source_t inputSource = (audio_source_t) data.readInt32();
             uint32_t samplingRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
             uint32_t channels = data.readInt32();
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 8c7a960..6b473c9 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -42,10 +42,11 @@
     {
     }
     
-    virtual status_t start()
+    virtual status_t start(pid_t tid)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+        data.writeInt32(tid);
         status_t status = remote()->transact(START, data, &reply);
         if (status == NO_ERROR) {
             status = reply.readInt32();
@@ -90,7 +91,7 @@
         } break;
         case START: {
             CHECK_INTERFACE(IAudioRecord, data, reply);
-            reply->writeInt32(start());
+            reply->writeInt32(start(data.readInt32()));
             return NO_ERROR;
         } break;
         case STOP: {
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index e618619..a7958de 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -1,4 +1,4 @@
-/* //device/extlibs/pv/android/IAudioTrack.cpp
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
@@ -58,10 +58,11 @@
         return cblk;
     }
 
-    virtual status_t start()
+    virtual status_t start(pid_t tid)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        data.writeInt32(tid);
         status_t status = remote()->transact(START, data, &reply);
         if (status == NO_ERROR) {
             status = reply.readInt32();
@@ -130,7 +131,7 @@
         } break;
         case START: {
             CHECK_INTERFACE(IAudioTrack, data, reply);
-            reply->writeInt32(start());
+            reply->writeInt32(start(data.readInt32()));
             return NO_ERROR;
         } break;
         case STOP: {
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index d2f5f71..27c7e03 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -59,9 +59,10 @@
         : BpInterface<IOMX>(impl) {
     }
 
-    virtual bool livesLocally(pid_t pid) {
+    virtual bool livesLocally(node_id node, pid_t pid) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        data.writeIntPtr((intptr_t)node);
         data.writeInt32(pid);
         remote()->transact(LIVES_LOCALLY, data, &reply);
 
@@ -417,7 +418,9 @@
         case LIVES_LOCALLY:
         {
             CHECK_INTERFACE(IOMX, data, reply);
-            reply->writeInt32(livesLocally((pid_t)data.readInt32()));
+            node_id node = (void *)data.readIntPtr();
+            pid_t pid = (pid_t)data.readInt32();
+            reply->writeInt32(livesLocally(node, pid));
 
             return OK;
         }
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 8456db5..6cb5b82 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -246,14 +246,12 @@
     }//while (1)
 
 threadExit:
-    if (mAudioTrack) {
+    if (mAudioTrack != NULL) {
         mAudioTrack->stop();
         mAudioTrack->flush();
     }
-    if (mAudioBuffer) {
-        delete [] mAudioBuffer;
-        mAudioBuffer = NULL;
-    }
+    delete [] mAudioBuffer;
+    mAudioBuffer = NULL;
     mMutex.lock();
     mTid = -1;
     mCondition.signal();
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index c905762..93ddca8 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -25,7 +25,7 @@
 #include <cutils/properties.h>
 #include <expat.h>
 #include <media/MediaProfiles.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/openmax/OMX_Video.h>
 
 namespace android {
@@ -349,7 +349,7 @@
 {
     CHECK(!strcmp("quality", atts[0]));
     int quality = atoi(atts[1]);
-    ALOGV("%s: cameraId=%d, quality=%d\n", __func__, cameraId, quality);
+    ALOGV("%s: cameraId=%d, quality=%d", __func__, cameraId, quality);
     ImageEncodingQualityLevels *levels = findImageEncodingQualityLevels(cameraId);
 
     if (levels == NULL) {
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 79cab74..73d4519 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -143,7 +143,7 @@
     if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
         strcpy(fileSpot, ".nomedia");
         if (access(path, F_OK) == 0) {
-            ALOGV("found .nomedia, setting noMedia flag\n");
+            ALOGV("found .nomedia, setting noMedia flag");
             noMedia = true;
         }
 
diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp
index 9fe1820..cdfd477 100644
--- a/media/libmedia/MediaScannerClient.cpp
+++ b/media/libmedia/MediaScannerClient.cpp
@@ -142,12 +142,12 @@
 
         UConverter *conv = ucnv_open(enc, &status);
         if (U_FAILURE(status)) {
-            ALOGE("could not create UConverter for %s\n", enc);
+            ALOGE("could not create UConverter for %s", enc);
             return;
         }
         UConverter *utf8Conv = ucnv_open("UTF-8", &status);
         if (U_FAILURE(status)) {
-            ALOGE("could not create UConverter for UTF-8\n");
+            ALOGE("could not create UConverter for UTF-8");
             ucnv_close(conv);
             return;
         }
@@ -181,7 +181,7 @@
             ucnv_convertEx(utf8Conv, conv, &target, target + targetLength,
                     &source, (const char *)dest, NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
             if (U_FAILURE(status)) {
-                ALOGE("ucnv_convertEx failed: %d\n", status);
+                ALOGE("ucnv_convertEx failed: %d", status);
                 mValues->setEntry(i, "???");
             } else {
                 // zero terminate
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 5ceb912..54eb98a 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -751,7 +751,7 @@
 
 // Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
 // to actual tone for current region.
-const unsigned char ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES] = {
+const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES] = {
         {   // ANSI
             TONE_ANSI_DIAL,             // TONE_SUP_DIAL
             TONE_ANSI_BUSY,             // TONE_SUP_BUSY
@@ -791,7 +791,7 @@
 //        generators, instantiates output audio track.
 //
 //    Input:
-//        streamType:        Type of stream used for tone playback (enum AudioTrack::stream_type)
+//        streamType:        Type of stream used for tone playback
 //        volume:            volume applied to tone (0.0 to 1.0)
 //
 //    Output:
@@ -800,7 +800,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool threadCanCallJava) {
 
-    ALOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume);
+    ALOGV("ToneGenerator constructor: streamType=%d, volume=%f", streamType, volume);
 
     mState = TONE_IDLE;
 
@@ -811,9 +811,9 @@
     mThreadCanCallJava = threadCanCallJava;
     mStreamType = streamType;
     mVolume = volume;
-    mpAudioTrack = 0;
-    mpToneDesc = 0;
-    mpNewToneDesc = 0;
+    mpAudioTrack = NULL;
+    mpToneDesc = NULL;
+    mpNewToneDesc = NULL;
     // Generate tone by chunks of 20 ms to keep cadencing precision
     mProcessSize = (mSamplingRate * 20) / 1000;
 
@@ -829,9 +829,9 @@
     }
 
     if (initAudioTrack()) {
-        ALOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
+        ALOGV("ToneGenerator INIT OK, time: %d", (unsigned int)(systemTime()/1000000));
     } else {
-        ALOGV("!!!ToneGenerator INIT FAILED!!!\n");
+        ALOGV("!!!ToneGenerator INIT FAILED!!!");
     }
 }
 
@@ -853,11 +853,11 @@
 //
 ////////////////////////////////////////////////////////////////////////////////
 ToneGenerator::~ToneGenerator() {
-    ALOGV("ToneGenerator destructor\n");
+    ALOGV("ToneGenerator destructor");
 
-    if (mpAudioTrack) {
+    if (mpAudioTrack != NULL) {
         stopTone();
-        ALOGV("Delete Track: %p\n", mpAudioTrack);
+        ALOGV("Delete Track: %p", mpAudioTrack);
         delete mpAudioTrack;
     }
 }
@@ -878,7 +878,7 @@
 //        none
 //
 ////////////////////////////////////////////////////////////////////////////////
-bool ToneGenerator::startTone(int toneType, int durationMs) {
+bool ToneGenerator::startTone(tone_type toneType, int durationMs) {
     bool lResult = false;
     status_t lStatus;
 
@@ -892,7 +892,7 @@
         }
     }
 
-    ALOGV("startTone\n");
+    ALOGV("startTone");
 
     mLock.lock();
 
@@ -915,7 +915,7 @@
 
     if (mState == TONE_INIT) {
         if (prepareWave()) {
-            ALOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
+            ALOGV("Immediate start, time %d", (unsigned int)(systemTime()/1000000));
             lResult = true;
             mState = TONE_STARTING;
             mLock.unlock();
@@ -934,7 +934,7 @@
             mState = TONE_IDLE;
         }
     } else {
-        ALOGV("Delayed start\n");
+        ALOGV("Delayed start");
         mState = TONE_RESTARTING;
         lStatus = mWaitCbkCond.waitRelative(mLock, seconds(3));
         if (lStatus == NO_ERROR) {
@@ -949,8 +949,8 @@
     }
     mLock.unlock();
 
-    ALOGV_IF(lResult, "Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
-    ALOGW_IF(!lResult, "Tone start failed!!!, time %d\n", (unsigned int)(systemTime()/1000000));
+    ALOGV_IF(lResult, "Tone started, time %d", (unsigned int)(systemTime()/1000000));
+    ALOGW_IF(!lResult, "Tone start failed!!!, time %d", (unsigned int)(systemTime()/1000000));
 
     return lResult;
 }
@@ -1012,12 +1012,12 @@
 
     if (mpAudioTrack) {
         delete mpAudioTrack;
-        mpAudioTrack = 0;
+        mpAudioTrack = NULL;
     }
 
    // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size
     mpAudioTrack = new AudioTrack();
-    ALOGV("Create Track: %p\n", mpAudioTrack);
+    ALOGV("Create Track: %p", mpAudioTrack);
 
     mpAudioTrack->set(mStreamType,
                       0,
@@ -1045,10 +1045,10 @@
 initAudioTrack_exit:
 
     // Cleanup
-    if (mpAudioTrack) {
-        ALOGV("Delete Track I: %p\n", mpAudioTrack);
+    if (mpAudioTrack != NULL) {
+        ALOGV("Delete Track I: %p", mpAudioTrack);
         delete mpAudioTrack;
-        mpAudioTrack = 0;
+        mpAudioTrack = NULL;
     }
 
     return false;
@@ -1141,7 +1141,7 @@
         if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
             // Time to go to next sequence segment
 
-            ALOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
+            ALOGV("End Segment, time: %d", (unsigned int)(systemTime()/1000000));
 
             lGenSmp = lReqSmp;
 
@@ -1156,13 +1156,13 @@
                     lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
                     lFrequency = lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[++lFreqIdx];
                 }
-                ALOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+                ALOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
             }
 
             // check if we need to loop and loop for the reqd times
             if (lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
                 if (lpToneGen->mLoopCounter < lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt) {
-                    ALOGV ("in if loop loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+                    ALOGV ("in if loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
                           lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
                           lpToneGen->mLoopCounter,
                           lpToneGen->mCurSegment);
@@ -1172,14 +1172,14 @@
                     // completed loop. go to next segment
                     lpToneGen->mLoopCounter = 0;
                     lpToneGen->mCurSegment++;
-                    ALOGV ("in else loop loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+                    ALOGV ("in else loop loopCnt(%d) loopctr(%d), CurSeg(%d)",
                           lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
                           lpToneGen->mLoopCounter,
                           lpToneGen->mCurSegment);
                 }
             } else {
                 lpToneGen->mCurSegment++;
-                ALOGV ("Goto next seg loopCnt(%d) loopctr(%d), CurSeg(%d) \n",
+                ALOGV ("Goto next seg loopCnt(%d) loopctr(%d), CurSeg(%d)",
                       lpToneDesc->segments[lpToneGen->mCurSegment].loopCnt,
                       lpToneGen->mLoopCounter,
                       lpToneGen->mCurSegment);
@@ -1188,32 +1188,32 @@
 
             // Handle loop if last segment reached
             if (lpToneDesc->segments[lpToneGen->mCurSegment].duration == 0) {
-                ALOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
+                ALOGV("Last Seg: %d", lpToneGen->mCurSegment);
 
                 // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
                 if (++lpToneGen->mCurCount <= lpToneDesc->repeatCnt) {
-                    ALOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
+                    ALOGV("Repeating Count: %d", lpToneGen->mCurCount);
 
                     lpToneGen->mCurSegment = lpToneDesc->repeatSegment;
                     if (lpToneDesc->segments[lpToneDesc->repeatSegment].waveFreq[0] != 0) {
                         lWaveCmd = WaveGenerator::WAVEGEN_START;
                     }
 
-                    ALOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+                    ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
                             (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
 
                 } else {
                     lGenSmp = 0;
-                    ALOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
+                    ALOGV("End repeat, time: %d", (unsigned int)(systemTime()/1000000));
                 }
             } else {
-                ALOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+                ALOGV("New segment %d, Next Time: %d", lpToneGen->mCurSegment,
                         (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
                 if (lpToneDesc->segments[lpToneGen->mCurSegment].waveFreq[0] != 0) {
                     // If next segment is not silent,  OFF -> ON transition : reset wave generator
                     lWaveCmd = WaveGenerator::WAVEGEN_START;
 
-                    ALOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+                    ALOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d", lGenSmp, lReqSmp);
                 } else {
                     lGenSmp = 0;
                 }
@@ -1251,13 +1251,13 @@
 
         switch (lpToneGen->mState) {
         case TONE_RESTARTING:
-            ALOGV("Cbk restarting track\n");
+            ALOGV("Cbk restarting track");
             if (lpToneGen->prepareWave()) {
                 lpToneGen->mState = TONE_STARTING;
                 // must reload lpToneDesc as prepareWave() may change mpToneDesc
                 lpToneDesc = lpToneGen->mpToneDesc;
             } else {
-                ALOGW("Cbk restarting prepareWave() failed\n");
+                ALOGW("Cbk restarting prepareWave() failed");
                 lpToneGen->mState = TONE_IDLE;
                 lpToneGen->mpAudioTrack->stop();
                 // Force loop exit
@@ -1266,14 +1266,14 @@
             lSignal = true;
             break;
         case TONE_STOPPING:
-            ALOGV("Cbk Stopping\n");
+            ALOGV("Cbk Stopping");
             lpToneGen->mState = TONE_STOPPED;
             // Force loop exit
             lNumSmp = 0;
             break;
         case TONE_STOPPED:
             lpToneGen->mState = TONE_INIT;
-            ALOGV("Cbk Stopped track\n");
+            ALOGV("Cbk Stopped track");
             lpToneGen->mpAudioTrack->stop();
             // Force loop exit
             lNumSmp = 0;
@@ -1281,7 +1281,7 @@
             lSignal = true;
             break;
         case TONE_STARTING:
-            ALOGV("Cbk starting track\n");
+            ALOGV("Cbk starting track");
             lpToneGen->mState = TONE_PLAYING;
             lSignal = true;
            break;
@@ -1317,7 +1317,7 @@
 bool ToneGenerator::prepareWave() {
     unsigned int segmentIdx = 0;
 
-    if (!mpNewToneDesc) {
+    if (mpNewToneDesc == NULL) {
         return false;
     }
 
@@ -1434,13 +1434,13 @@
 //        none
 //
 ////////////////////////////////////////////////////////////////////////////////
-int ToneGenerator::getToneForRegion(int toneType) {
-    int regionTone;
+ToneGenerator::tone_type ToneGenerator::getToneForRegion(tone_type toneType) {
+    tone_type regionTone;
 
     if (mRegion == CEPT || toneType < FIRST_SUP_TONE || toneType > LAST_SUP_TONE) {
         regionTone = toneType;
     } else {
-        regionTone = sToneMappingTable[mRegion][toneType - FIRST_SUP_TONE];
+        regionTone = (tone_type) sToneMappingTable[mRegion][toneType - FIRST_SUP_TONE];
     }
 
     ALOGV("getToneForRegion, tone %d, region %d, regionTone %d", toneType, mRegion, regionTone);
@@ -1491,7 +1491,7 @@
         d0 = 32767;
     mA1_Q14 = (short) d0;
 
-    ALOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d\n",
+    ALOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d",
             mA1_Q14, mS2_0, mAmplitude_Q15);
 }
 
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index f1c47dd..250425b 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -1,4 +1,4 @@
-/* mediaplayer.cpp
+/*
 **
 ** Copyright 2006, The Android Open Source Project
 **
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a0c20ae..4df7f3d 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1265,6 +1265,8 @@
     mStreamType = AUDIO_STREAM_MUSIC;
     mLeftVolume = 1.0;
     mRightVolume = 1.0;
+    mPlaybackRatePermille = 1000;
+    mSampleRateHz = 0;
     mLatency = 0;
     mMsecsPerFrame = 0;
     mAuxEffectId = 0;
@@ -1402,10 +1404,15 @@
     ALOGV("setVolume");
     t->setVolume(mLeftVolume, mRightVolume);
 
-    mMsecsPerFrame = 1.e3 / (float) sampleRate;
+    mSampleRateHz = sampleRate;
+    mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
     mLatency = t->latency();
     mTrack = t;
 
+    status_t res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
+    if (res != NO_ERROR) {
+        return res;
+    }
     t->setAuxEffectSendLevel(mSendLevel);
     return t->attachAuxEffect(mAuxEffectId);;
 }
@@ -1469,6 +1476,22 @@
     }
 }
 
+status_t MediaPlayerService::AudioOutput::setPlaybackRatePermille(int32_t ratePermille)
+{
+    ALOGV("setPlaybackRatePermille(%d)", ratePermille);
+    status_t res = NO_ERROR;
+    if (mTrack) {
+        res = mTrack->setSampleRate(ratePermille * mSampleRateHz / 1000);
+    } else {
+        res = NO_INIT;
+    }
+    mPlaybackRatePermille = ratePermille;
+    if (mSampleRateHz != 0) {
+        mMsecsPerFrame = mPlaybackRatePermille / (float) mSampleRateHz;
+    }
+    return res;
+}
+
 status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
 {
     ALOGV("setAuxEffectSendLevel(%f)", level);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index fa71d11..52af64d 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -95,6 +95,7 @@
         virtual void            close();
                 void            setAudioStreamType(audio_stream_type_t streamType) { mStreamType = streamType; }
                 void            setVolume(float left, float right);
+        virtual status_t        setPlaybackRatePermille(int32_t ratePermille);
                 status_t        setAuxEffectSendLevel(float level);
                 status_t        attachAuxEffect(int effectId);
         virtual status_t        dump(int fd, const Vector<String16>& args) const;
@@ -112,6 +113,8 @@
         audio_stream_type_t     mStreamType;
         float                   mLeftVolume;
         float                   mRightVolume;
+        int32_t                 mPlaybackRatePermille;
+        uint32_t                mSampleRateHz; // sample rate of the content, as set in open()
         float                   mMsecsPerFrame;
         uint32_t                mLatency;
         int                     mSessionId;
@@ -152,6 +155,7 @@
         virtual void            close() {}
                 void            setAudioStreamType(audio_stream_type_t streamType) {}
                 void            setVolume(float left, float right) {}
+        virtual status_t        setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
                 uint32_t        sampleRate() const { return mSampleRate; }
                 audio_format_t  format() const { return mFormat; }
                 size_t          size() const { return mSize; }
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 6d7771a..052ebf0 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -176,7 +176,7 @@
 }
 
 status_t StagefrightPlayer::setParameter(int key, const Parcel &request) {
-    ALOGV("setParameter");
+    ALOGV("setParameter(key=%d)", key);
     return mPlayer->setParameter(key, request);
 }
 
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 4632016..fe519b0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -24,6 +24,7 @@
 #include <binder/IServiceManager.h>
 
 #include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/AACWriter.h>
@@ -31,7 +32,6 @@
 #include <media/stagefright/CameraSourceTimeLapse.h>
 #include <media/stagefright/MPEG2TSWriter.h>
 #include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXClient.h>
@@ -241,8 +241,8 @@
 status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
     ALOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
     // These don't make any sense, do they?
-    CHECK_EQ(offset, 0);
-    CHECK_EQ(length, 0);
+    CHECK_EQ(offset, 0ll);
+    CHECK_EQ(length, 0ll);
 
     if (fd < 0) {
         ALOGE("Invalid file descriptor: %d", fd);
@@ -734,7 +734,7 @@
 }
 
 status_t StagefrightRecorder::start() {
-    CHECK(mOutputFd >= 0);
+    CHECK_GE(mOutputFd, 0);
 
     if (mWriter != NULL) {
         ALOGE("File writer is not avaialble");
@@ -837,7 +837,7 @@
     }
 
     OMXClient client;
-    CHECK_EQ(client.connect(), OK);
+    CHECK_EQ(client.connect(), (status_t)OK);
 
     sp<MediaSource> audioEncoder =
         OMXCodec::Create(client.interface(), encMeta,
@@ -850,9 +850,9 @@
 status_t StagefrightRecorder::startAACRecording() {
     // FIXME:
     // Add support for OUTPUT_FORMAT_AAC_ADIF
-    CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
+    CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS);
 
-    CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
+    CHECK_EQ(mAudioEncoder, AUDIO_ENCODER_AAC);
     CHECK(mAudioSource != AUDIO_SOURCE_CNT);
 
     mWriter = new AACWriter(mOutputFd);
@@ -1386,7 +1386,7 @@
     }
 
     OMXClient client;
-    CHECK_EQ(client.connect(), OK);
+    CHECK_EQ(client.connect(), (status_t)OK);
 
     uint32_t encoder_flags = 0;
     if (mIsMetaDataStoredInVideoBuffers) {
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 33f22f2..4d1072f 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -23,9 +23,9 @@
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 1673ccd..9cdb463 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -60,7 +60,7 @@
 
 AACWriter::~AACWriter() {
     if (mStarted) {
-        stop();
+        reset();
     }
 
     if (mFd != -1) {
@@ -152,7 +152,7 @@
     return OK;
 }
 
-status_t AACWriter::stop() {
+status_t AACWriter::reset() {
     if (!mStarted) {
         return OK;
     }
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 5a28347..03dcbf9 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -20,9 +20,9 @@
 
 #include "include/AMRExtractor.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 6c4e307..ca85640 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/AMRWriter.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>
@@ -52,7 +52,7 @@
 
 AMRWriter::~AMRWriter() {
     if (mStarted) {
-        stop();
+        reset();
     }
 
     if (mFd != -1) {
@@ -152,7 +152,7 @@
     return OK;
 }
 
-status_t AMRWriter::stop() {
+status_t AMRWriter::reset() {
     if (!mStarted) {
         return OK;
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 0aeb515..483e5ab 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -74,12 +74,11 @@
         libcrypto        \
         libssl           \
         libgui           \
+        libstagefright_omx \
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_color_conversion \
         libstagefright_aacenc \
-        libstagefright_amrnbenc \
-        libstagefright_amrwbenc \
         libstagefright_avcenc \
         libstagefright_m4vh263enc \
         libstagefright_matroska \
@@ -141,7 +140,6 @@
 ################################################################################
 
 LOCAL_SHARED_LIBRARIES += \
-        libstagefright_amrnb_common \
         libstagefright_enc_common \
         libstagefright_avc_common \
         libstagefright_foundation \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 9a9c3ef..df27566 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -268,6 +268,16 @@
     return mReachedEOS;
 }
 
+status_t AudioPlayer::setPlaybackRatePermille(int32_t ratePermille) {
+    if (mAudioSink.get() != NULL) {
+        return mAudioSink->setPlaybackRatePermille(ratePermille);
+    } else if (mAudioTrack != NULL){
+        return mAudioTrack->setSampleRate(ratePermille * mSampleRate / 1000);
+    } else {
+        return NO_INIT;
+    }
+}
+
 // static
 size_t AudioPlayer::AudioSinkCallback(
         MediaPlayerBase::AudioSink *audioSink,
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 2172cc0..fef2a00 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -47,7 +47,7 @@
 }
 
 AudioSource::AudioSource(
-        int inputSource, uint32_t sampleRate, uint32_t channels)
+        audio_source_t inputSource, uint32_t sampleRate, uint32_t channels)
     : mStarted(false),
       mSampleRate(sampleRate),
       mPrevSampleTimeUs(0),
@@ -72,7 +72,7 @@
 
 AudioSource::~AudioSource() {
     if (mStarted) {
-        stop();
+        reset();
     }
 
     delete mRecord;
@@ -130,7 +130,7 @@
     }
 }
 
-status_t AudioSource::stop() {
+status_t AudioSource::reset() {
     Mutex::Autolock autoLock(mLock);
     if (!mStarted) {
         return UNKNOWN_ERROR;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8480b6d..70945e3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -30,7 +30,7 @@
 #include "include/MPEG2TSExtractor.h"
 #include "include/WVMExtractor.h"
 
-#include "timedtext/TimedTextPlayer.h"
+#include "timedtext/TimedTextDriver.h"
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -192,7 +192,7 @@
       mVideoBuffer(NULL),
       mDecryptHandle(NULL),
       mLastVideoTimeUs(-1),
-      mTextPlayer(NULL) {
+      mTextDriver(NULL) {
     CHECK_EQ(mClient.connect(), (status_t)OK);
 
     DataSource::RegisterDefaultSniffers();
@@ -530,9 +530,9 @@
     delete mAudioPlayer;
     mAudioPlayer = NULL;
 
-    if (mTextPlayer != NULL) {
-        delete mTextPlayer;
-        mTextPlayer = NULL;
+    if (mTextDriver != NULL) {
+        delete mTextDriver;
+        mTextDriver = NULL;
     }
 
     mVideoRenderer.clear();
@@ -1118,7 +1118,7 @@
     }
 
     if (mFlags & TEXTPLAYER_STARTED) {
-        mTextPlayer->pause();
+        mTextDriver->pause();
         modifyFlags(TEXT_RUNNING, CLEAR);
     }
 
@@ -1272,9 +1272,9 @@
 }
 
 status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) {
-    if (mTextPlayer != NULL) {
+    if (mTextDriver != NULL) {
         if (index >= 0) { // to turn on a text track
-            status_t err = mTextPlayer->setTimedTextTrackIndex(index);
+            status_t err = mTextDriver->setTimedTextTrackIndex(index);
             if (err != OK) {
                 return err;
             }
@@ -1290,7 +1290,7 @@
                 modifyFlags(TEXTPLAYER_STARTED, CLEAR);
             }
 
-            return mTextPlayer->setTimedTextTrackIndex(index);
+            return mTextDriver->setTimedTextTrackIndex(index);
         }
     } else {
         return INVALID_OPERATION;
@@ -1319,7 +1319,7 @@
     seekAudioIfNecessary_l();
 
     if (mFlags & TEXTPLAYER_STARTED) {
-        mTextPlayer->seekTo(mSeekTimeUs);
+        mTextDriver->seekToAsync(mSeekTimeUs);
     }
 
     if (!(mFlags & PLAYING)) {
@@ -1360,15 +1360,15 @@
     mAudioTrack = source;
 }
 
-void AwesomePlayer::addTextSource(sp<MediaSource> source) {
+void AwesomePlayer::addTextSource(const sp<MediaSource>& source) {
     Mutex::Autolock autoLock(mTimedTextLock);
     CHECK(source != NULL);
 
-    if (mTextPlayer == NULL) {
-        mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+    if (mTextDriver == NULL) {
+        mTextDriver = new TimedTextDriver(mListener);
     }
 
-    mTextPlayer->addTextSource(source);
+    mTextDriver->addInBandTextSource(source);
 }
 
 status_t AwesomePlayer::initAudioDecoder() {
@@ -1609,7 +1609,7 @@
                     mSeekTimeUs,
                     mSeeking == SEEK_VIDEO_ONLY
                         ? MediaSource::ReadOptions::SEEK_NEXT_SYNC
-                        : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+                        : MediaSource::ReadOptions::SEEK_CLOSEST);
         }
         for (;;) {
             status_t err = mVideoSource->read(&mVideoBuffer, &options);
@@ -1695,7 +1695,7 @@
     }
 
     if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
-        mTextPlayer->resume();
+        mTextDriver->resume();
         modifyFlags(TEXT_RUNNING, SET);
     }
 
@@ -2241,16 +2241,24 @@
         case KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE:
         {
             Mutex::Autolock autoLock(mTimedTextLock);
-            if (mTextPlayer == NULL) {
-                mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+            if (mTextDriver == NULL) {
+                mTextDriver = new TimedTextDriver(mListener);
             }
 
-            return mTextPlayer->setParameter(key, request);
+            return mTextDriver->addOutOfBandTextSource(request);
         }
         case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
         {
             return setCacheStatCollectFreq(request);
         }
+        case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE:
+        {
+            if (mAudioPlayer != NULL) {
+                return mAudioPlayer->setPlaybackRatePermille(request.readInt32());
+            } else {
+                return NO_INIT;
+            }
+        }
         default:
         {
             return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 1850c9c..ed1d5f4 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -20,8 +20,8 @@
 
 #include <OMX_Component.h>
 #include <binder/IPCThreadState.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/CameraSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -114,7 +114,7 @@
     ALOGE("Uknown color format (%s), please add it to "
          "CameraSource::getColorFormat", colorFormat);
 
-    CHECK_EQ(0, "Unknown color format");
+    CHECK(!"Unknown color format");
 }
 
 CameraSource *CameraSource::Create() {
@@ -517,7 +517,7 @@
 
     // This CHECK is good, since we just passed the lock/unlock
     // check earlier by calling mCamera->setParameters().
-    CHECK_EQ(OK, mCamera->setPreviewDisplay(mSurface));
+    CHECK_EQ((status_t)OK, mCamera->setPreviewDisplay(mSurface));
 
     // By default, do not store metadata in video buffers
     mIsMetaDataStoredInVideoBuffers = false;
@@ -548,7 +548,7 @@
 
 CameraSource::~CameraSource() {
     if (mStarted) {
-        stop();
+        reset();
     } else if (mInitCheck == OK) {
         // Camera is initialized but because start() is never called,
         // the lock on Camera is never released(). This makes sure
@@ -566,7 +566,8 @@
     if (mCameraFlags & FLAGS_HOT_CAMERA) {
         mCamera->unlock();
         mCamera.clear();
-        CHECK_EQ(OK, mCameraRecordingProxy->startRecording(new ProxyListener(this)));
+        CHECK_EQ((status_t)OK,
+            mCameraRecordingProxy->startRecording(new ProxyListener(this)));
     } else {
         mCamera->setListener(new CameraSourceListener(this));
         mCamera->startRecording();
@@ -632,8 +633,8 @@
     mCameraFlags = 0;
 }
 
-status_t CameraSource::stop() {
-    ALOGD("stop: E");
+status_t CameraSource::reset() {
+    ALOGD("reset: E");
     Mutex::Autolock autoLock(mLock);
     mStarted = false;
     mFrameAvailableCondition.signal();
@@ -670,7 +671,7 @@
     }
 
     CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
-    ALOGD("stop: X");
+    ALOGD("reset: X");
     return OK;
 }
 
@@ -718,7 +719,7 @@
             return;
         }
     }
-    CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+    CHECK(!"signalBufferReturned: bogus buffer");
 }
 
 status_t CameraSource::read(
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 263ab50..26ce7ae 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -20,9 +20,9 @@
 #include <binder/IPCThreadState.h>
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/CameraSourceTimeLapse.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MetaData.h>
 #include <camera/Camera.h>
 #include <camera/CameraParameters.h>
@@ -87,6 +87,10 @@
 }
 
 CameraSourceTimeLapse::~CameraSourceTimeLapse() {
+    if (mLastReadBufferCopy) {
+        mLastReadBufferCopy->release();
+        mLastReadBufferCopy = NULL;
+    }
 }
 
 void CameraSourceTimeLapse::startQuickReadReturns() {
@@ -204,15 +208,6 @@
     }
 }
 
-void CameraSourceTimeLapse::stopCameraRecording() {
-    ALOGV("stopCameraRecording");
-    CameraSource::stopCameraRecording();
-    if (mLastReadBufferCopy) {
-        mLastReadBufferCopy->release();
-        mLastReadBufferCopy = NULL;
-    }
-}
-
 sp<IMemory> CameraSourceTimeLapse::createIMemoryCopy(
         const sp<IMemory> &source_data) {
 
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index afc4a80..524c3aa 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -23,6 +23,7 @@
 
 #include <arpa/inet.h>
 #include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaSource.h>
@@ -30,7 +31,6 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
 
 #include <drm/drm_framework_common.h>
 #include <utils/Errors.h>
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 01f53e4..73c8d03 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/types.h>
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index e818115..bafa4b2 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -18,10 +18,10 @@
 #define LOG_TAG "JPEGSource"
 #include <utils/Log.h>
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/JPEGSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -59,7 +59,7 @@
       mWidth(0),
       mHeight(0),
       mOffset(0) {
-    CHECK_EQ(parseJPEG(), OK);
+    CHECK_EQ(parseJPEG(), (status_t)OK);
     CHECK(mSource->getSize(&mSize) == OK);
 }
 
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 36009ab..0b4ecbe 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -513,7 +513,7 @@
 
 MPEG2TSWriter::~MPEG2TSWriter() {
     if (mStarted) {
-        stop();
+        reset();
     }
 
     mLooper->unregisterHandler(mReflector->id());
@@ -564,7 +564,7 @@
     return OK;
 }
 
-status_t MPEG2TSWriter::stop() {
+status_t MPEG2TSWriter::reset() {
     CHECK(mStarted);
 
     for (size_t i = 0; i < mSources.size(); ++i) {
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index bc88015..6c95d4e5 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -20,7 +20,6 @@
 #include "include/MPEG4Extractor.h"
 #include "include/SampleTable.h"
 #include "include/ESDS.h"
-#include "timedtext/TimedTextPlayer.h"
 
 #include <arpa/inet.h>
 
@@ -2430,4 +2429,3 @@
 }
 
 }  // namespace android
-
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 06dd875..7ebbe1d 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -23,10 +23,10 @@
 #include <pthread.h>
 #include <sys/prctl.h>
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
@@ -70,6 +70,10 @@
     status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
+    enum {
+        kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
+    };
+
     MPEG4Writer *mOwner;
     sp<MetaData> mMeta;
     sp<MediaSource> mSource;
@@ -137,11 +141,12 @@
             : sampleCount(count), sampleDuration(timescaledDur) {}
 
         uint32_t sampleCount;
-        int32_t sampleDuration;  // time scale based
+        uint32_t sampleDuration;  // time scale based
     };
-    bool          mHasNegativeCttsDeltaDuration;
     size_t        mNumCttsTableEntries;
     List<CttsTableEntry> mCttsTableEntries;
+    int64_t mMinCttsOffsetTimeUs;
+    int64_t mMaxCttsOffsetTimeUs;
 
     // Sequence parameter set or picture parameter set
     struct AVCParamSet {
@@ -172,6 +177,8 @@
     // Update the audio track's drift information.
     void updateDriftTime(const sp<MetaData>& meta);
 
+    int32_t getStartTimeOffsetScaledTime() const;
+
     static void *ThreadWrapper(void *me);
     status_t threadEntry();
 
@@ -282,7 +289,7 @@
 }
 
 MPEG4Writer::~MPEG4Writer() {
-    stop();
+    reset();
 
     while (!mTracks.empty()) {
         List<Track *>::iterator it = mTracks.begin();
@@ -471,7 +478,7 @@
         !param->findInt32(kKeyTimeScale, &mTimeScale)) {
         mTimeScale = 1000;
     }
-    CHECK(mTimeScale > 0);
+    CHECK_GT(mTimeScale, 0);
     ALOGV("movie time scale: %d", mTimeScale);
 
     mStreamableFile = true;
@@ -490,7 +497,7 @@
         }
         mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
     }
-    CHECK(mEstimatedMoovBoxSize >= 8);
+    CHECK_GE(mEstimatedMoovBoxSize, 8);
     lseek64(mFd, mFreeBoxOffset, SEEK_SET);
     writeInt32(mEstimatedMoovBoxSize);
     write("free", 4);
@@ -616,7 +623,7 @@
     mStarted = false;
 }
 
-status_t MPEG4Writer::stop() {
+status_t MPEG4Writer::reset() {
     if (mInitCheck != OK) {
         return OK;
     } else {
@@ -684,7 +691,7 @@
 
     mWriteMoovBoxToMemory = false;
     if (mStreamableFile) {
-        CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
+        CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
 
         // Moov box
         lseek64(mFd, mFreeBoxOffset, SEEK_SET);
@@ -856,7 +863,7 @@
 
         mOffset += length + 4;
     } else {
-        CHECK(length < 65536);
+        CHECK_LT(length, 65536);
 
         uint8_t x = length >> 8;
         ::write(mFd, &x, 1);
@@ -1085,7 +1092,7 @@
 
 void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
     ALOGI("setStartTimestampUs: %lld", timeUs);
-    CHECK(timeUs >= 0);
+    CHECK_GE(timeUs, 0ll);
     Mutex::Autolock autoLock(mLock);
     if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
         mStartTimestampUs = timeUs;
@@ -1186,9 +1193,6 @@
     if (mIsAudio) {
         return;
     }
-    if (duration < 0 && !mHasNegativeCttsDeltaDuration) {
-        mHasNegativeCttsDeltaDuration = true;
-    }
     CttsTableEntry cttsEntry(sampleCount, duration);
     mCttsTableEntries.push_back(cttsEntry);
     ++mNumCttsTableEntries;
@@ -1218,7 +1222,7 @@
         mTimeScale = timeScale;
     }
 
-    CHECK(mTimeScale > 0);
+    CHECK_GT(mTimeScale, 0);
 }
 
 void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
@@ -1299,7 +1303,7 @@
         }
     }
 
-    CHECK("Received a chunk for a unknown track" == 0);
+    CHECK(!"Received a chunk for a unknown track");
 }
 
 void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
@@ -1509,7 +1513,6 @@
     mMdatSizeBytes = 0;
 
     mMaxChunkDurationUs = 0;
-    mHasNegativeCttsDeltaDuration = false;
 
     pthread_create(&mThread, &attr, ThreadWrapper, this);
     pthread_attr_destroy(&attr);
@@ -1833,29 +1836,18 @@
     int32_t nChunks = 0;
     int32_t nZeroLengthFrames = 0;
     int64_t lastTimestampUs = 0;      // Previous sample time stamp
-    int64_t lastCttsTimeUs = 0;       // Previous sample time stamp
     int64_t lastDurationUs = 0;       // Between the previous two samples
     int64_t currDurationTicks = 0;    // Timescale based ticks
     int64_t lastDurationTicks = 0;    // Timescale based ticks
     int32_t sampleCount = 1;          // Sample count in the current stts table entry
-    int64_t currCttsDurTicks = 0;     // Timescale based ticks
-    int64_t lastCttsDurTicks = 0;     // Timescale based ticks
-    int32_t cttsSampleCount = 1;      // Sample count in the current ctts table entry
-    uint32_t previousSampleSize = 0;      // Size of the previous sample
+    uint32_t previousSampleSize = 0;  // Size of the previous sample
     int64_t previousPausedDurationUs = 0;
     int64_t timestampUs = 0;
-    int64_t cttsDeltaTimeUs = 0;
-    bool hasBFrames = false;
+    int64_t cttsOffsetTimeUs = 0;
+    int64_t currCttsOffsetTimeTicks = 0;   // Timescale based ticks
+    int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
+    int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
 
-#if 1
-    // XXX: Samsung's video encoder's output buffer timestamp
-    // is not correct. see bug 4724339
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("rw.media.record.hasb", value, NULL) &&
-        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
-        hasBFrames = true;
-    }
-#endif
     if (mIsAudio) {
         prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
     } else {
@@ -1897,7 +1889,7 @@
                         (const uint8_t *)buffer->data()
                             + buffer->range_offset(),
                         buffer->range_length());
-                CHECK_EQ(OK, err);
+                CHECK_EQ((status_t)OK, err);
             } else if (mIsMPEG4) {
                 mCodecSpecificDataSize = buffer->range_length();
                 mCodecSpecificData = malloc(mCodecSpecificDataSize);
@@ -1963,32 +1955,64 @@
 
         if (mResumed) {
             int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
-            CHECK(durExcludingEarlierPausesUs >= 0);
+            CHECK_GE(durExcludingEarlierPausesUs, 0ll);
             int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
-            CHECK(pausedDurationUs >= lastDurationUs);
+            CHECK_GE(pausedDurationUs, lastDurationUs);
             previousPausedDurationUs += pausedDurationUs - lastDurationUs;
             mResumed = false;
         }
 
         timestampUs -= previousPausedDurationUs;
-        CHECK(timestampUs >= 0);
-        if (!mIsAudio && hasBFrames) {
+        CHECK_GE(timestampUs, 0ll);
+        if (!mIsAudio) {
             /*
              * Composition time: timestampUs
              * Decoding time: decodingTimeUs
-             * Composition time delta = composition time - decoding time
-             *
-             * We save picture decoding time stamp delta in stts table entries,
-             * and composition time delta duration in ctts table entries.
+             * Composition time offset = composition time - decoding time
              */
             int64_t decodingTimeUs;
             CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
             decodingTimeUs -= previousPausedDurationUs;
-            int64_t timeUs = decodingTimeUs;
-            cttsDeltaTimeUs = timestampUs - decodingTimeUs;
+            cttsOffsetTimeUs =
+                    timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
+            CHECK_GE(cttsOffsetTimeUs, 0ll);
             timestampUs = decodingTimeUs;
-            ALOGV("decoding time: %lld and ctts delta time: %lld",
-                timestampUs, cttsDeltaTimeUs);
+            ALOGV("decoding time: %lld and ctts offset time: %lld",
+                timestampUs, cttsOffsetTimeUs);
+
+            // Update ctts box table if necessary
+            currCttsOffsetTimeTicks =
+                    (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
+            CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL);
+            if (mNumSamples == 0) {
+                // Force the first ctts table entry to have one single entry
+                // so that we can do adjustment for the initial track start
+                // time offset easily in writeCttsBox().
+                lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
+                addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
+                cttsSampleCount = 0;      // No sample in ctts box is pending
+            } else {
+                if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
+                    addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+                    lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
+                    cttsSampleCount = 1;  // One sample in ctts box is pending
+                } else {
+                    ++cttsSampleCount;
+                }
+            }
+
+            // Update ctts time offset range
+            if (mNumSamples == 0) {
+                mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+                mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+            } else {
+                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
+                    mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
+                    mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
+                }
+            }
+
         }
 
         if (mIsRealTimeRecording) {
@@ -1997,7 +2021,7 @@
             }
         }
 
-        CHECK(timestampUs >= 0);
+        CHECK_GE(timestampUs, 0ll);
         ALOGV("%s media time stamp: %lld and previous paused duration %lld",
                 mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
         if (timestampUs > mTrackDurationUs) {
@@ -2012,6 +2036,7 @@
         currDurationTicks =
             ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
                 (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
+        CHECK_GE(currDurationTicks, 0ll);
 
         mSampleSizes.push_back(sampleSize);
         ++mNumSamples;
@@ -2020,25 +2045,12 @@
             // Force the first sample to have its own stts entry so that
             // we can adjust its value later to maintain the A/V sync.
             if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) {
-                ALOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us",
-                        mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks);
                 addOneSttsTableEntry(sampleCount, lastDurationTicks);
                 sampleCount = 1;
             } else {
                 ++sampleCount;
             }
 
-            if (!mIsAudio) {
-                currCttsDurTicks =
-                     ((cttsDeltaTimeUs * mTimeScale + 500000LL) / 1000000LL -
-                     (lastCttsTimeUs * mTimeScale + 500000LL) / 1000000LL);
-                if (currCttsDurTicks != lastCttsDurTicks) {
-                    addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
-                    cttsSampleCount = 1;
-                } else {
-                    ++cttsSampleCount;
-                }
-            }
         }
         if (mSamplesHaveSameSize) {
             if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
@@ -2052,11 +2064,6 @@
         lastDurationTicks = currDurationTicks;
         lastTimestampUs = timestampUs;
 
-        if (!mIsAudio) {
-            lastCttsDurTicks = currCttsDurTicks;
-            lastCttsTimeUs = cttsDeltaTimeUs;
-        }
-
         if (isSync != 0) {
             addOneStssTableEntry(mNumSamples);
         }
@@ -2125,10 +2132,8 @@
     if (mNumSamples == 1) {
         lastDurationUs = 0;  // A single sample's duration
         lastDurationTicks = 0;
-        lastCttsDurTicks = 0;
     } else {
         ++sampleCount;  // Count for the last sample
-        ++cttsSampleCount;
     }
 
     if (mNumSamples <= 2) {
@@ -2140,7 +2145,14 @@
         addOneSttsTableEntry(sampleCount, lastDurationTicks);
     }
 
-    addOneCttsTableEntry(cttsSampleCount, lastCttsDurTicks);
+    // The last ctts box may not have been written yet, and this
+    // is to make sure that we write out the last ctts box.
+    if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
+        if (cttsSampleCount > 0) {
+            addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+        }
+    }
+
     mTrackDurationUs += lastDurationUs;
     mReachedEOS = true;
 
@@ -2406,7 +2418,7 @@
     mOwner->writeInt16(0x18);        // depth
     mOwner->writeInt16(-1);          // predefined
 
-    CHECK(23 + mCodecSpecificDataSize < 128);
+    CHECK_LT(23 + mCodecSpecificDataSize, 128);
 
     if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
         writeMp4vEsdsBox();
@@ -2465,10 +2477,10 @@
 void MPEG4Writer::Track::writeMp4aEsdsBox() {
     mOwner->beginBox("esds");
     CHECK(mCodecSpecificData);
-    CHECK(mCodecSpecificDataSize > 0);
+    CHECK_GT(mCodecSpecificDataSize, 0);
 
     // Make sure all sizes encode to a single byte.
-    CHECK(mCodecSpecificDataSize + 23 < 128);
+    CHECK_LT(mCodecSpecificDataSize + 23, 128);
 
     mOwner->writeInt32(0);     // version=0, flags=0
     mOwner->writeInt8(0x03);   // ES_DescrTag
@@ -2502,7 +2514,7 @@
 
 void MPEG4Writer::Track::writeMp4vEsdsBox() {
     CHECK(mCodecSpecificData);
-    CHECK(mCodecSpecificDataSize > 0);
+    CHECK_GT(mCodecSpecificDataSize, 0);
     mOwner->beginBox("esds");
 
     mOwner->writeInt32(0);    // version=0, flags=0
@@ -2662,7 +2674,7 @@
 
 void MPEG4Writer::Track::writeAvccBox() {
     CHECK(mCodecSpecificData);
-    CHECK(mCodecSpecificDataSize >= 5);
+    CHECK_GE(mCodecSpecificDataSize, 5);
 
     // Patch avcc's lengthSize field to match the number
     // of bytes we use to indicate the size of a nal unit.
@@ -2690,23 +2702,26 @@
     mOwner->endBox();  // pasp
 }
 
+int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
+    int64_t trackStartTimeOffsetUs = 0;
+    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
+    if (mStartTimestampUs != moovStartTimeUs) {
+        CHECK_GT(mStartTimestampUs, moovStartTimeUs);
+        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
+    }
+    return (trackStartTimeOffsetUs *  mTimeScale + 500000LL) / 1000000LL;
+}
+
 void MPEG4Writer::Track::writeSttsBox() {
     mOwner->beginBox("stts");
     mOwner->writeInt32(0);  // version=0, flags=0
     mOwner->writeInt32(mNumSttsTableEntries);
 
     // Compensate for small start time difference from different media tracks
-    int64_t trackStartTimeOffsetUs = 0;
-    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
-    if (mStartTimestampUs != moovStartTimeUs) {
-        CHECK(mStartTimestampUs > moovStartTimeUs);
-        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
-    }
     List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
     CHECK(it != mSttsTableEntries.end() && it->sampleCount == 1);
     mOwner->writeInt32(it->sampleCount);
-    int32_t dur = (trackStartTimeOffsetUs * mTimeScale + 500000LL) / 1000000LL;
-    mOwner->writeInt32(dur + it->sampleDuration);
+    mOwner->writeInt32(getStartTimeOffsetScaledTime() + it->sampleDuration);
 
     int64_t totalCount = 1;
     while (++it != mSttsTableEntries.end()) {
@@ -2714,7 +2729,7 @@
         mOwner->writeInt32(it->sampleDuration);
         totalCount += it->sampleCount;
     }
-    CHECK(totalCount == mNumSamples);
+    CHECK_EQ(totalCount, mNumSamples);
     mOwner->endBox();  // stts
 }
 
@@ -2723,6 +2738,11 @@
         return;
     }
 
+    // There is no B frame at all
+    if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
+        return;
+    }
+
     // Do not write ctts box when there is no need to have it.
     if ((mNumCttsTableEntries == 1 &&
         mCttsTableEntries.begin()->sampleDuration == 0) ||
@@ -2730,24 +2750,29 @@
         return;
     }
 
-    ALOGV("ctts box has %d entries", mNumCttsTableEntries);
+    ALOGD("ctts box has %d entries with range [%lld, %lld]",
+            mNumCttsTableEntries, mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
 
     mOwner->beginBox("ctts");
-    if (mHasNegativeCttsDeltaDuration) {
-        mOwner->writeInt32(0x00010000);  // version=1, flags=0
-    } else {
-        mOwner->writeInt32(0);  // version=0, flags=0
-    }
+    // Version 1 allows to use negative offset time value, but
+    // we are sticking to version 0 for now.
+    mOwner->writeInt32(0);  // version=0, flags=0
     mOwner->writeInt32(mNumCttsTableEntries);
 
-    int64_t totalCount = 0;
-    for (List<CttsTableEntry>::iterator it = mCttsTableEntries.begin();
-         it != mCttsTableEntries.end(); ++it) {
+    // Compensate for small start time difference from different media tracks
+    List<CttsTableEntry>::iterator it = mCttsTableEntries.begin();
+    CHECK(it != mCttsTableEntries.end() && it->sampleCount == 1);
+    mOwner->writeInt32(it->sampleCount);
+    mOwner->writeInt32(getStartTimeOffsetScaledTime() +
+            it->sampleDuration - mMinCttsOffsetTimeUs);
+
+    int64_t totalCount = 1;
+    while (++it != mCttsTableEntries.end()) {
         mOwner->writeInt32(it->sampleCount);
-        mOwner->writeInt32(it->sampleDuration);
+        mOwner->writeInt32(it->sampleDuration - mMinCttsOffsetTimeUs);
         totalCount += it->sampleCount;
     }
-    CHECK(totalCount == mNumSamples);
+    CHECK_EQ(totalCount, mNumSamples);
     mOwner->endBox();  // ctts
 }
 
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index 96271e4..11b80bf 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -22,8 +22,8 @@
 #include <stdlib.h>
 
 #include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MetaData.h>
 
 #include <ui/GraphicBuffer.h>
@@ -157,7 +157,7 @@
 }
 
 MediaBuffer::~MediaBuffer() {
-    CHECK_EQ(mObserver, NULL);
+    CHECK(mObserver == NULL);
 
     if (mOwnsData && mData != NULL) {
         free(mData);
@@ -188,7 +188,7 @@
 }
 
 MediaBuffer *MediaBuffer::clone() {
-    CHECK_EQ(mGraphicBuffer, NULL);
+    CHECK(mGraphicBuffer == NULL);
 
     MediaBuffer *buffer = new MediaBuffer(mData, mSize);
     buffer->set_range(mRangeOffset, mRangeLength);
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
index c8d05f4..80aae51 100644
--- a/media/libstagefright/MediaBufferGroup.cpp
+++ b/media/libstagefright/MediaBufferGroup.cpp
@@ -17,9 +17,9 @@
 #define LOG_TAG "MediaBufferGroup"
 #include <utils/Log.h>
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 
 namespace android {
 
diff --git a/media/libstagefright/MediaSourceSplitter.cpp b/media/libstagefright/MediaSourceSplitter.cpp
index 8af0694..3b64ded 100644
--- a/media/libstagefright/MediaSourceSplitter.cpp
+++ b/media/libstagefright/MediaSourceSplitter.cpp
@@ -18,8 +18,8 @@
 #define LOG_TAG "MediaSourceSplitter"
 #include <utils/Log.h>
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaSourceSplitter.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 884f3b4..66dec90 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -17,7 +17,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MetaData.h>
 
 namespace android {
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 9de873e..7a805aa 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -20,11 +20,299 @@
 
 #include <binder/IServiceManager.h>
 #include <media/IMediaPlayerService.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/OMXClient.h>
+#include <utils/KeyedVector.h>
+
+#include "include/OMX.h"
 
 namespace android {
 
+struct MuxOMX : public IOMX {
+    MuxOMX(const sp<IOMX> &remoteOMX);
+    virtual ~MuxOMX();
+
+    virtual IBinder *onAsBinder() { return NULL; }
+
+    virtual bool livesLocally(node_id node, pid_t pid);
+
+    virtual status_t listNodes(List<ComponentInfo> *list);
+
+    virtual status_t allocateNode(
+            const char *name, const sp<IOMXObserver> &observer,
+            node_id *node);
+
+    virtual status_t freeNode(node_id node);
+
+    virtual status_t sendCommand(
+            node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
+
+    virtual status_t getParameter(
+            node_id node, OMX_INDEXTYPE index,
+            void *params, size_t size);
+
+    virtual status_t setParameter(
+            node_id node, OMX_INDEXTYPE index,
+            const void *params, size_t size);
+
+    virtual status_t getConfig(
+            node_id node, OMX_INDEXTYPE index,
+            void *params, size_t size);
+
+    virtual status_t setConfig(
+            node_id node, OMX_INDEXTYPE index,
+            const void *params, size_t size);
+
+    virtual status_t getState(
+            node_id node, OMX_STATETYPE* state);
+
+    virtual status_t storeMetaDataInBuffers(
+            node_id node, OMX_U32 port_index, OMX_BOOL enable);
+
+    virtual status_t enableGraphicBuffers(
+            node_id node, OMX_U32 port_index, OMX_BOOL enable);
+
+    virtual status_t getGraphicBufferUsage(
+            node_id node, OMX_U32 port_index, OMX_U32* usage);
+
+    virtual status_t useBuffer(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer);
+
+    virtual status_t useGraphicBuffer(
+            node_id node, OMX_U32 port_index,
+            const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer);
+
+    virtual status_t allocateBuffer(
+            node_id node, OMX_U32 port_index, size_t size,
+            buffer_id *buffer, void **buffer_data);
+
+    virtual status_t allocateBufferWithBackup(
+            node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+            buffer_id *buffer);
+
+    virtual status_t freeBuffer(
+            node_id node, OMX_U32 port_index, buffer_id buffer);
+
+    virtual status_t fillBuffer(node_id node, buffer_id buffer);
+
+    virtual status_t emptyBuffer(
+            node_id node,
+            buffer_id buffer,
+            OMX_U32 range_offset, OMX_U32 range_length,
+            OMX_U32 flags, OMX_TICKS timestamp);
+
+    virtual status_t getExtensionIndex(
+            node_id node,
+            const char *parameter_name,
+            OMX_INDEXTYPE *index);
+
+private:
+    mutable Mutex mLock;
+
+    sp<IOMX> mRemoteOMX;
+    sp<IOMX> mLocalOMX;
+
+    KeyedVector<node_id, bool> mIsLocalNode;
+
+    bool isLocalNode(node_id node) const;
+    bool isLocalNode_l(node_id node) const;
+    const sp<IOMX> &getOMX(node_id node) const;
+    const sp<IOMX> &getOMX_l(node_id node) const;
+
+    static bool IsSoftwareComponent(const char *name);
+
+    DISALLOW_EVIL_CONSTRUCTORS(MuxOMX);
+};
+
+MuxOMX::MuxOMX(const sp<IOMX> &remoteOMX)
+    : mRemoteOMX(remoteOMX) {
+}
+
+MuxOMX::~MuxOMX() {
+}
+
+bool MuxOMX::isLocalNode(node_id node) const {
+    Mutex::Autolock autoLock(mLock);
+
+    return isLocalNode_l(node);
+}
+
+bool MuxOMX::isLocalNode_l(node_id node) const {
+    return mIsLocalNode.indexOfKey(node) >= 0;
+}
+
+// static
+bool MuxOMX::IsSoftwareComponent(const char *name) {
+    return !strncasecmp(name, "OMX.google.", 11);
+}
+
+const sp<IOMX> &MuxOMX::getOMX(node_id node) const {
+    return isLocalNode(node) ? mLocalOMX : mRemoteOMX;
+}
+
+const sp<IOMX> &MuxOMX::getOMX_l(node_id node) const {
+    return isLocalNode_l(node) ? mLocalOMX : mRemoteOMX;
+}
+
+bool MuxOMX::livesLocally(node_id node, pid_t pid) {
+    return getOMX(node)->livesLocally(node, pid);
+}
+
+status_t MuxOMX::listNodes(List<ComponentInfo> *list) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mLocalOMX == NULL) {
+        mLocalOMX = new OMX;
+    }
+
+    return mLocalOMX->listNodes(list);
+}
+
+status_t MuxOMX::allocateNode(
+        const char *name, const sp<IOMXObserver> &observer,
+        node_id *node) {
+    Mutex::Autolock autoLock(mLock);
+
+    sp<IOMX> omx;
+
+    if (IsSoftwareComponent(name)) {
+        if (mLocalOMX == NULL) {
+            mLocalOMX = new OMX;
+        }
+        omx = mLocalOMX;
+    } else {
+        omx = mRemoteOMX;
+    }
+
+    status_t err = omx->allocateNode(name, observer, node);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (omx == mLocalOMX) {
+        mIsLocalNode.add(*node, true);
+    }
+
+    return OK;
+}
+
+status_t MuxOMX::freeNode(node_id node) {
+    Mutex::Autolock autoLock(mLock);
+
+    status_t err = getOMX_l(node)->freeNode(node);
+
+    if (err != OK) {
+        return err;
+    }
+
+    mIsLocalNode.removeItem(node);
+
+    return OK;
+}
+
+status_t MuxOMX::sendCommand(
+        node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+    return getOMX(node)->sendCommand(node, cmd, param);
+}
+
+status_t MuxOMX::getParameter(
+        node_id node, OMX_INDEXTYPE index,
+        void *params, size_t size) {
+    return getOMX(node)->getParameter(node, index, params, size);
+}
+
+status_t MuxOMX::setParameter(
+        node_id node, OMX_INDEXTYPE index,
+        const void *params, size_t size) {
+    return getOMX(node)->setParameter(node, index, params, size);
+}
+
+status_t MuxOMX::getConfig(
+        node_id node, OMX_INDEXTYPE index,
+        void *params, size_t size) {
+    return getOMX(node)->getConfig(node, index, params, size);
+}
+
+status_t MuxOMX::setConfig(
+        node_id node, OMX_INDEXTYPE index,
+        const void *params, size_t size) {
+    return getOMX(node)->setConfig(node, index, params, size);
+}
+
+status_t MuxOMX::getState(
+        node_id node, OMX_STATETYPE* state) {
+    return getOMX(node)->getState(node, state);
+}
+
+status_t MuxOMX::storeMetaDataInBuffers(
+        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+    return getOMX(node)->storeMetaDataInBuffers(node, port_index, enable);
+}
+
+status_t MuxOMX::enableGraphicBuffers(
+        node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+    return getOMX(node)->enableGraphicBuffers(node, port_index, enable);
+}
+
+status_t MuxOMX::getGraphicBufferUsage(
+        node_id node, OMX_U32 port_index, OMX_U32* usage) {
+    return getOMX(node)->getGraphicBufferUsage(node, port_index, usage);
+}
+
+status_t MuxOMX::useBuffer(
+        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+        buffer_id *buffer) {
+    return getOMX(node)->useBuffer(node, port_index, params, buffer);
+}
+
+status_t MuxOMX::useGraphicBuffer(
+        node_id node, OMX_U32 port_index,
+        const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
+    return getOMX(node)->useGraphicBuffer(
+            node, port_index, graphicBuffer, buffer);
+}
+
+status_t MuxOMX::allocateBuffer(
+        node_id node, OMX_U32 port_index, size_t size,
+        buffer_id *buffer, void **buffer_data) {
+    return getOMX(node)->allocateBuffer(
+            node, port_index, size, buffer, buffer_data);
+}
+
+status_t MuxOMX::allocateBufferWithBackup(
+        node_id node, OMX_U32 port_index, const sp<IMemory> &params,
+        buffer_id *buffer) {
+    return getOMX(node)->allocateBufferWithBackup(
+            node, port_index, params, buffer);
+}
+
+status_t MuxOMX::freeBuffer(
+        node_id node, OMX_U32 port_index, buffer_id buffer) {
+    return getOMX(node)->freeBuffer(node, port_index, buffer);
+}
+
+status_t MuxOMX::fillBuffer(node_id node, buffer_id buffer) {
+    return getOMX(node)->fillBuffer(node, buffer);
+}
+
+status_t MuxOMX::emptyBuffer(
+        node_id node,
+        buffer_id buffer,
+        OMX_U32 range_offset, OMX_U32 range_length,
+        OMX_U32 flags, OMX_TICKS timestamp) {
+    return getOMX(node)->emptyBuffer(
+            node, buffer, range_offset, range_length, flags, timestamp);
+}
+
+status_t MuxOMX::getExtensionIndex(
+        node_id node,
+        const char *parameter_name,
+        OMX_INDEXTYPE *index) {
+    return getOMX(node)->getExtensionIndex(node, parameter_name, index);
+}
+
 OMXClient::OMXClient() {
 }
 
@@ -38,6 +326,11 @@
     mOMX = service->getOMX();
     CHECK(mOMX.get() != NULL);
 
+    if (!mOMX->livesLocally(NULL /* node */, getpid())) {
+        ALOGI("Using client-side OMX mux.");
+        mOMX = new MuxOMX(mOMX);
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 60d9bb7..470f750 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -19,8 +19,6 @@
 #include <utils/Log.h>
 
 #include "include/AACEncoder.h"
-#include "include/AMRNBEncoder.h"
-#include "include/AMRWBEncoder.h"
 #include "include/AVCEncoder.h"
 #include "include/M4vH263Encoder.h"
 
@@ -71,8 +69,6 @@
 
 #define FACTORY_REF(name) { #name, Make##name },
 
-FACTORY_CREATE_ENCODER(AMRNBEncoder)
-FACTORY_CREATE_ENCODER(AMRWBEncoder)
 FACTORY_CREATE_ENCODER(AACEncoder)
 FACTORY_CREATE_ENCODER(AVCEncoder)
 FACTORY_CREATE_ENCODER(M4vH263Encoder)
@@ -86,8 +82,6 @@
     };
 
     static const FactoryInfo kFactoryInfo[] = {
-        FACTORY_REF(AMRNBEncoder)
-        FACTORY_REF(AMRWBEncoder)
         FACTORY_REF(AACEncoder)
         FACTORY_REF(AVCEncoder)
         FACTORY_REF(M4vH263Encoder)
@@ -149,10 +143,11 @@
 
 static const CodecInfo kEncoderInfo[] = {
     { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
-    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBEncoder" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.encoder" },
     { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
-    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBEncoder" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.encoder" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.encoder" },
     { MEDIA_MIMETYPE_AUDIO_AAC, "AACEncoder" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.MPEG4E" },
     { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" },
@@ -1482,11 +1477,12 @@
         const sp<MediaSource> &source,
         const sp<ANativeWindow> &nativeWindow)
     : mOMX(omx),
-      mOMXLivesLocally(omx->livesLocally(getpid())),
+      mOMXLivesLocally(omx->livesLocally(node, getpid())),
       mNode(node),
       mQuirks(quirks),
       mFlags(flags),
       mIsEncoder(isEncoder),
+      mIsVideo(!strncasecmp("video/", mime, 6)),
       mMIME(strdup(mime)),
       mComponentName(strdup(componentName)),
       mSource(source),
@@ -2191,8 +2187,8 @@
     }
 }
 
-int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
-    CHECK(mIsEncoder);
+int64_t OMXCodec::getDecodingTimeUs() {
+    CHECK(mIsEncoder && mIsVideo);
 
     if (mDecodingTimeList.empty()) {
         CHECK(mSignalledEOS || mNoMoreOutputData);
@@ -2203,12 +2199,7 @@
 
     List<int64_t>::iterator it = mDecodingTimeList.begin();
     int64_t timeUs = *it;
-
-    // If the output buffer is codec specific configuration,
-    // do not remove the decoding time from the list.
-    if (!isCodecSpecific) {
-        mDecodingTimeList.erase(it);
-    }
+    mDecodingTimeList.erase(it);
     return timeUs;
 }
 
@@ -2387,8 +2378,8 @@
                     mNoMoreOutputData = true;
                 }
 
-                if (mIsEncoder) {
-                    int64_t decodingTimeUs = retrieveDecodingTimeUs(isCodecSpecific);
+                if (mIsEncoder && mIsVideo) {
+                    int64_t decodingTimeUs = isCodecSpecific? 0: getDecodingTimeUs();
                     buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
                 }
 
@@ -3249,7 +3240,7 @@
         int64_t lastBufferTimeUs;
         CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs));
         CHECK(lastBufferTimeUs >= 0);
-        if (mIsEncoder) {
+        if (mIsEncoder && mIsVideo) {
             mDecodingTimeList.push_back(lastBufferTimeUs);
         }
 
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 73efc27..5e79e78 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -21,10 +21,10 @@
 #include "include/OggExtractor.h"
 
 #include <cutils/properties.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 81ec5c1..eae721b 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -22,8 +22,8 @@
 
 #include <arpa/inet.h>
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/Utils.h>
 
 #include "include/SampleTable.h"
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 43bfd9e..35f9c1f 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -20,10 +20,10 @@
 
 #include "include/StagefrightMetadataRetriever.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/ColorConverter.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXCodec.h>
@@ -37,7 +37,7 @@
     ALOGV("StagefrightMetadataRetriever()");
 
     DataSource::RegisterDefaultSniffers();
-    CHECK_EQ(mClient.connect(), OK);
+    CHECK_EQ(mClient.connect(), (status_t)OK);
 }
 
 StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
@@ -169,7 +169,7 @@
              || (buffer != NULL && buffer->range_length() == 0));
 
     if (err != OK) {
-        CHECK_EQ(buffer, NULL);
+        CHECK(buffer == NULL);
 
         ALOGV("decoding frame failed.");
         decoder->stop();
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 2233d1b..aa047d6 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -16,14 +16,14 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "SurfaceMediaSource"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/SurfaceMediaSource.h>
-#include <ui/GraphicBuffer.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/openmax/OMX_IVCommon.h>
 #include <media/stagefright/MetadataBufferType.h>
 
+#include <ui/GraphicBuffer.h>
 #include <surfaceflinger/ISurfaceComposer.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
 #include <surfaceflinger/IGraphicBufferAlloc.h>
@@ -60,7 +60,7 @@
 SurfaceMediaSource::~SurfaceMediaSource() {
     ALOGV("SurfaceMediaSource::~SurfaceMediaSource");
     if (!mStopped) {
-        stop();
+        reset();
     }
 }
 
@@ -716,9 +716,9 @@
 }
 
 
-status_t SurfaceMediaSource::stop()
+status_t SurfaceMediaSource::reset()
 {
-    ALOGV("Stop");
+    ALOGV("Reset");
 
     Mutex::Autolock lock(mMutex);
     // TODO: Add waiting on mFrameCompletedCondition here?
@@ -855,7 +855,7 @@
     }
 
     if (!foundBuffer) {
-        CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+        CHECK(!"signalBufferReturned: bogus buffer");
     }
 }
 
diff --git a/media/libstagefright/ThrottledSource.cpp b/media/libstagefright/ThrottledSource.cpp
index 88e07b0..b1fcafd 100644
--- a/media/libstagefright/ThrottledSource.cpp
+++ b/media/libstagefright/ThrottledSource.cpp
@@ -16,7 +16,7 @@
 
 #include "include/ThrottledSource.h"
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
 
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 12c9c36..f4b5d4f 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -31,7 +31,7 @@
 #include <sys/prctl.h>
 #include <sys/time.h>
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 
 #ifdef ANDROID_SIMULATOR
 #include <jni.h>
diff --git a/media/libstagefright/VideoSourceDownSampler.cpp b/media/libstagefright/VideoSourceDownSampler.cpp
index 1b669904..90a42c9 100644
--- a/media/libstagefright/VideoSourceDownSampler.cpp
+++ b/media/libstagefright/VideoSourceDownSampler.cpp
@@ -17,9 +17,9 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "VideoSourceDownSampler"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/VideoSourceDownSampler.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/YUVImage.h>
 #include <media/stagefright/YUVCanvas.h>
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 0bcaf08..501f4806 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -20,9 +20,9 @@
 
 #include "include/WAVExtractor.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
@@ -217,7 +217,7 @@
                                 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
                         break;
                     default:
-                        CHECK_EQ(mWaveFormat, WAVE_FORMAT_MULAW);
+                        CHECK_EQ(mWaveFormat, (uint16_t)WAVE_FORMAT_MULAW);
                         mTrackMeta->setCString(
                                 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
                         break;
@@ -362,7 +362,7 @@
             // Convert 8-bit unsigned samples to 16-bit signed.
 
             MediaBuffer *tmp;
-            CHECK_EQ(mGroup->acquire_buffer(&tmp), OK);
+            CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK);
 
             // The new buffer holds the sample number of samples, but each
             // one is 2 bytes wide.
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 1e4e049..c7ad513 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -21,6 +21,7 @@
 
 #include <arpa/inet.h>
 #include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaSource.h>
@@ -28,7 +29,6 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
 #include <dlfcn.h>
 
 #include <utils/Errors.h>
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
index da9d280..ea6c360 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
@@ -218,6 +218,18 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamAudioPcm:
+        {
+            const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalSetParameter(index, params);
     }
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index 2b8633d..8b5007e 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -22,8 +22,8 @@
 #include "voAAC.h"
 #include "cmnMemory.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -114,8 +114,8 @@
     ALOGV("setAudioSpecificConfigData: %d hz, %d bps, and %d channels",
          mSampleRate, mBitRate, mChannels);
 
-    int32_t index;
-    CHECK_EQ(OK, getSampleRateTableIndex(mSampleRate, index));
+    int32_t index = 0;
+    CHECK_EQ((status_t)OK, getSampleRateTableIndex(mSampleRate, index));
     if (mChannels > 2 || mChannels <= 0) {
         ALOGE("Unsupported number of channels(%d)", mChannels);
         return UNKNOWN_ERROR;
@@ -142,7 +142,7 @@
     mBufferGroup = new MediaBufferGroup;
     mBufferGroup->add_buffer(new MediaBuffer(2048));
 
-    CHECK_EQ(OK, initCheck());
+    CHECK_EQ((status_t)OK, initCheck());
 
     mNumInputSamples = 0;
     mAnchorTimeUs = 0;
@@ -183,7 +183,7 @@
 
     mSource->stop();
     if (mEncoderHandle) {
-        CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+        CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
         mEncoderHandle = NULL;
     }
     delete mApiHandle;
@@ -223,7 +223,7 @@
     CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
 
     MediaBuffer *buffer;
-    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
     uint8_t *outPtr = (uint8_t *)buffer->data();
     bool readFromSource = false;
     int64_t wallClockTimeUs = -1;
@@ -255,7 +255,7 @@
             }
 
             size_t align = mInputBuffer->range_length() % sizeof(int16_t);
-            CHECK_EQ(align, 0);
+            CHECK_EQ(align, (size_t)0);
 
             int64_t timeUs;
             if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 8318ba4..34a2796 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -85,3 +85,29 @@
 endif
 
 include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+        SoftAACEncoder.cpp
+
+LOCAL_C_INCLUDES := \
+        frameworks/base/media/libstagefright/include \
+        frameworks/base/include/media/stagefright/openmax \
+	frameworks/base/media/libstagefright/codecs/common/include \
+
+LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
+
+LOCAL_STATIC_LIBRARIES := \
+        libstagefright_aacenc
+
+LOCAL_SHARED_LIBRARIES := \
+        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_enc_common
+
+LOCAL_MODULE := libstagefright_soft_aacenc
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
new file mode 100644
index 0000000..c6724c26
--- /dev/null
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2012 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 "SoftAACEncoder"
+#include <utils/Log.h>
+
+#include "SoftAACEncoder.h"
+
+#include "voAAC.h"
+#include "cmnMemory.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+
+namespace android {
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftAACEncoder::SoftAACEncoder(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mEncoderHandle(NULL),
+      mApiHandle(NULL),
+      mMemOperator(NULL),
+      mNumChannels(1),
+      mSampleRate(44100),
+      mBitRate(0),
+      mSentCodecSpecificData(false),
+      mInputSize(0),
+      mInputFrame(NULL),
+      mInputTimeUs(-1ll),
+      mSawInputEOS(false),
+      mSignalledError(false) {
+    initPorts();
+    CHECK_EQ(initEncoder(), (status_t)OK);
+
+    setAudioParams();
+}
+
+SoftAACEncoder::~SoftAACEncoder() {
+    delete[] mInputFrame;
+    mInputFrame = NULL;
+
+    if (mEncoderHandle) {
+        CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+        mEncoderHandle = NULL;
+    }
+
+    delete mApiHandle;
+    mApiHandle = NULL;
+
+    delete mMemOperator;
+    mMemOperator = NULL;
+}
+
+void SoftAACEncoder::initPorts() {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 2;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 8192;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/aac");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
+
+    addPort(def);
+}
+
+status_t SoftAACEncoder::initEncoder() {
+    mApiHandle = new VO_AUDIO_CODECAPI;
+
+    if (VO_ERR_NONE != voGetAACEncAPI(mApiHandle)) {
+        ALOGE("Failed to get api handle");
+        return UNKNOWN_ERROR;
+    }
+
+    mMemOperator = new VO_MEM_OPERATOR;
+    mMemOperator->Alloc = cmnMemAlloc;
+    mMemOperator->Copy = cmnMemCopy;
+    mMemOperator->Free = cmnMemFree;
+    mMemOperator->Set = cmnMemSet;
+    mMemOperator->Check = cmnMemCheck;
+
+    VO_CODEC_INIT_USERDATA userData;
+    memset(&userData, 0, sizeof(userData));
+    userData.memflag = VO_IMF_USERMEMOPERATOR;
+    userData.memData = (VO_PTR) mMemOperator;
+    if (VO_ERR_NONE !=
+            mApiHandle->Init(&mEncoderHandle, VO_AUDIO_CodingAAC, &userData)) {
+        ALOGE("Failed to init AAC encoder");
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+OMX_ERRORTYPE SoftAACEncoder::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            formatParams->eEncoding =
+                (formatParams->nPortIndex == 0)
+                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAac:
+        {
+            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
+                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+            if (aacParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            aacParams->nBitRate = mBitRate;
+            aacParams->nAudioBandWidth = 0;
+            aacParams->nAACtools = 0;
+            aacParams->nAACERtools = 0;
+            aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
+            aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+            aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+
+            aacParams->nChannels = mNumChannels;
+            aacParams->nSampleRate = mSampleRate;
+            aacParams->nFrameLength = 0;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eEndian = OMX_EndianBig;
+            pcmParams->bInterleaved = OMX_TRUE;
+            pcmParams->nBitPerSample = 16;
+            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+            pcmParams->nChannels = mNumChannels;
+            pcmParams->nSamplingRate = mSampleRate;
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftAACEncoder::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (strncmp((const char *)roleParams->cRole,
+                        "audio_encoder.aac",
+                        OMX_MAX_STRINGNAME_SIZE - 1)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPortFormat:
+        {
+            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            if ((formatParams->nPortIndex == 0
+                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+                || (formatParams->nPortIndex == 1
+                        && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAac:
+        {
+            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
+                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+            if (aacParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            mBitRate = aacParams->nBitRate;
+            mNumChannels = aacParams->nChannels;
+            mSampleRate = aacParams->nSampleRate;
+
+            if (setAudioParams() != OK) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            mNumChannels = pcmParams->nChannels;
+            mSampleRate = pcmParams->nSamplingRate;
+
+            if (setAudioParams() != OK) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+status_t SoftAACEncoder::setAudioParams() {
+    // We call this whenever sample rate, number of channels or bitrate change
+    // in reponse to setParameter calls.
+
+    ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps",
+         mSampleRate, mNumChannels, mBitRate);
+
+    status_t err = setAudioSpecificConfigData();
+
+    if (err != OK) {
+        return err;
+    }
+
+    AACENC_PARAM params;
+    memset(&params, 0, sizeof(params));
+    params.sampleRate = mSampleRate;
+    params.bitRate = mBitRate;
+    params.nChannels = mNumChannels;
+    params.adtsUsed = 0;  // We add adts header in the file writer if needed.
+    if (VO_ERR_NONE != mApiHandle->SetParam(
+                mEncoderHandle, VO_PID_AAC_ENCPARAM,  &params)) {
+        ALOGE("Failed to set AAC encoder parameters");
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+static status_t getSampleRateTableIndex(int32_t sampleRate, int32_t &index) {
+    static const int32_t kSampleRateTable[] = {
+        96000, 88200, 64000, 48000, 44100, 32000,
+        24000, 22050, 16000, 12000, 11025, 8000
+    };
+    const int32_t tableSize =
+        sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]);
+
+    for (int32_t i = 0; i < tableSize; ++i) {
+        if (sampleRate == kSampleRateTable[i]) {
+            index = i;
+            return OK;
+        }
+    }
+
+    return UNKNOWN_ERROR;
+}
+
+status_t SoftAACEncoder::setAudioSpecificConfigData() {
+    // The AAC encoder's audio specific config really only encodes
+    // number of channels and the sample rate (mapped to an index into
+    // a fixed sample rate table).
+
+    int32_t index;
+    status_t err = getSampleRateTableIndex(mSampleRate, index);
+    if (err != OK) {
+        ALOGE("Unsupported sample rate (%lu Hz)", mSampleRate);
+        return err;
+    }
+
+    if (mNumChannels > 2 || mNumChannels <= 0) {
+        ALOGE("Unsupported number of channels(%lu)", mNumChannels);
+        return UNKNOWN_ERROR;
+    }
+
+    // OMX_AUDIO_AACObjectLC
+    mAudioSpecificConfigData[0] = ((0x02 << 3) | (index >> 1));
+    mAudioSpecificConfigData[1] = ((index & 0x01) << 7) | (mNumChannels << 3);
+
+    return OK;
+}
+
+void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) {
+    if (mSignalledError) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    if (!mSentCodecSpecificData) {
+        // The very first thing we want to output is the codec specific
+        // data. It does not require any input data but we will need an
+        // output buffer to store it in.
+
+        if (outQueue.empty()) {
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+        outHeader->nFilledLen = sizeof(mAudioSpecificConfigData);
+        outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
+
+        uint8_t *out = outHeader->pBuffer + outHeader->nOffset;
+        memcpy(out, mAudioSpecificConfigData, sizeof(mAudioSpecificConfigData));
+
+#if 0
+        ALOGI("sending codec specific data.");
+        hexdump(out, sizeof(mAudioSpecificConfigData));
+#endif
+
+        outQueue.erase(outQueue.begin());
+        outInfo->mOwnedByUs = false;
+        notifyFillBufferDone(outHeader);
+
+        mSentCodecSpecificData = true;
+    }
+
+    size_t numBytesPerInputFrame =
+        mNumChannels * kNumSamplesPerFrame * sizeof(int16_t);
+
+    for (;;) {
+        // We do the following until we run out of buffers.
+
+        while (mInputSize < numBytesPerInputFrame) {
+            // As long as there's still input data to be read we
+            // will drain "kNumSamplesPerFrame * mNumChannels" samples
+            // into the "mInputFrame" buffer and then encode those
+            // as a unit into an output buffer.
+
+            if (mSawInputEOS || inQueue.empty()) {
+                return;
+            }
+
+            BufferInfo *inInfo = *inQueue.begin();
+            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+            const void *inData = inHeader->pBuffer + inHeader->nOffset;
+
+            size_t copy = numBytesPerInputFrame - mInputSize;
+            if (copy > inHeader->nFilledLen) {
+                copy = inHeader->nFilledLen;
+            }
+
+            if (mInputFrame == NULL) {
+                mInputFrame = new int16_t[kNumSamplesPerFrame * mNumChannels];
+            }
+
+            if (mInputSize == 0) {
+                mInputTimeUs = inHeader->nTimeStamp;
+            }
+
+            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
+            mInputSize += copy;
+
+            inHeader->nOffset += copy;
+            inHeader->nFilledLen -= copy;
+
+            // "Time" on the input buffer has in effect advanced by the
+            // number of audio frames we just advanced nOffset by.
+            inHeader->nTimeStamp +=
+                (copy * 1000000ll / mSampleRate)
+                    / (mNumChannels * sizeof(int16_t));
+
+            if (inHeader->nFilledLen == 0) {
+                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                    ALOGV("saw input EOS");
+                    mSawInputEOS = true;
+
+                    // Pad any remaining data with zeroes.
+                    memset((uint8_t *)mInputFrame + mInputSize,
+                           0,
+                           numBytesPerInputFrame - mInputSize);
+
+                    mInputSize = numBytesPerInputFrame;
+                }
+
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+
+                inData = NULL;
+                inHeader = NULL;
+                inInfo = NULL;
+            }
+        }
+
+        // At this  point we have all the input data necessary to encode
+        // a single frame, all we need is an output buffer to store the result
+        // in.
+
+        if (outQueue.empty()) {
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+        VO_CODECBUFFER inputData;
+        memset(&inputData, 0, sizeof(inputData));
+        inputData.Buffer = (unsigned char *)mInputFrame;
+        inputData.Length = numBytesPerInputFrame;
+        CHECK(VO_ERR_NONE ==
+                mApiHandle->SetInputData(mEncoderHandle, &inputData));
+
+        VO_CODECBUFFER outputData;
+        memset(&outputData, 0, sizeof(outputData));
+        VO_AUDIO_OUTPUTINFO outputInfo;
+        memset(&outputInfo, 0, sizeof(outputInfo));
+
+        uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset;
+        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
+
+        VO_U32 ret = VO_ERR_NONE;
+        size_t nOutputBytes = 0;
+        do {
+            outputData.Buffer = outPtr;
+            outputData.Length = outAvailable - nOutputBytes;
+            ret = mApiHandle->GetOutputData(
+                    mEncoderHandle, &outputData, &outputInfo);
+            if (ret == VO_ERR_NONE) {
+                outPtr += outputData.Length;
+                nOutputBytes += outputData.Length;
+            }
+        } while (ret != VO_ERR_INPUT_BUFFER_SMALL);
+
+        outHeader->nFilledLen = nOutputBytes;
+
+        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
+
+        if (mSawInputEOS) {
+            // We also tag this output buffer with EOS if it corresponds
+            // to the final input buffer.
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        }
+
+        outHeader->nTimeStamp = mInputTimeUs;
+
+#if 0
+        ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
+              nOutputBytes, mInputTimeUs, outHeader->nFlags);
+
+        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
+#endif
+
+        outQueue.erase(outQueue.begin());
+        outInfo->mOwnedByUs = false;
+        notifyFillBufferDone(outHeader);
+
+        outHeader = NULL;
+        outInfo = NULL;
+
+        mInputSize = 0;
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    return new android::SoftAACEncoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
new file mode 100644
index 0000000..d148eb7
--- /dev/null
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012 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 SOFT_AAC_ENCODER_H_
+
+#define SOFT_AAC_ENCODER_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+struct VO_AUDIO_CODECAPI;
+struct VO_MEM_OPERATOR;
+
+namespace android {
+
+struct SoftAACEncoder : public SimpleSoftOMXComponent {
+    SoftAACEncoder(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftAACEncoder();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+    enum {
+        kNumBuffers             = 4,
+        kNumSamplesPerFrame     = 1024,
+    };
+
+    void *mEncoderHandle;
+    VO_AUDIO_CODECAPI *mApiHandle;
+    VO_MEM_OPERATOR  *mMemOperator;
+
+    OMX_U32 mNumChannels;
+    OMX_U32 mSampleRate;
+    OMX_U32 mBitRate;
+
+    bool mSentCodecSpecificData;
+    size_t mInputSize;
+    int16_t *mInputFrame;
+    int64_t mInputTimeUs;
+
+    bool mSawInputEOS;
+
+    uint8_t mAudioSpecificConfigData[2];
+
+    bool mSignalledError;
+
+    void initPorts();
+    status_t initEncoder();
+
+    status_t setAudioSpecificConfigData();
+    status_t setAudioParams();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftAACEncoder);
+};
+
+}  // namespace android
+
+#endif  // SOFT_AAC_ENCODER_H_
diff --git a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
index e48af9d..982f4fd 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
+++ b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
@@ -358,4 +358,4 @@
   res = pow2Table[(POW2_TABLE_SIZE*fPart)/y] >> iPart;
 
   return(res);
-}
\ No newline at end of file
+}
diff --git a/media/libstagefright/codecs/aacenc/basic_op/typedefs.h b/media/libstagefright/codecs/aacenc/basic_op/typedefs.h
index c924e2c..2d5d956 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/typedefs.h
+++ b/media/libstagefright/codecs/aacenc/basic_op/typedefs.h
@@ -77,12 +77,12 @@
 /*
  ********* define 32 bit signed/unsigned types & constants
  */
-typedef long Word32;
-typedef unsigned long UWord32;
+typedef int Word32;
+typedef unsigned int UWord32;
 
 
 
-#ifdef LINUX
+#ifndef _MSC_VER
 typedef long long Word64;
 typedef unsigned long long UWord64;
 #else
diff --git a/media/libstagefright/codecs/aacenc/inc/config.h b/media/libstagefright/codecs/aacenc/inc/config.h
index 3b29cef..b0b4c26 100644
--- a/media/libstagefright/codecs/aacenc/inc/config.h
+++ b/media/libstagefright/codecs/aacenc/inc/config.h
@@ -33,4 +33,4 @@
 #define MINBITS_COEF		744
 
 
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libstagefright/codecs/aacenc/inc/sf_estim.h b/media/libstagefright/codecs/aacenc/inc/sf_estim.h
index 9039f25..997eba5 100644
--- a/media/libstagefright/codecs/aacenc/inc/sf_estim.h
+++ b/media/libstagefright/codecs/aacenc/inc/sf_estim.h
@@ -43,4 +43,4 @@
                      Word16          logSfbFormFactor[MAX_CHANNELS][MAX_GROUPED_SFB],
                      Word16          sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],
                      const Word16    nChannels);
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libstagefright/codecs/aacenc/inc/transform.h b/media/libstagefright/codecs/aacenc/inc/transform.h
index fbac7aa..311cef5 100644
--- a/media/libstagefright/codecs/aacenc/inc/transform.h
+++ b/media/libstagefright/codecs/aacenc/inc/transform.h
@@ -33,4 +33,4 @@
                     Word16 windowSequence
                     );
 
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libstagefright/codecs/aacenc/src/aac_rom.c b/media/libstagefright/codecs/aacenc/src/aac_rom.c
index 08792e8..127322d 100644
--- a/media/libstagefright/codecs/aacenc/src/aac_rom.c
+++ b/media/libstagefright/codecs/aacenc/src/aac_rom.c
@@ -2360,4 +2360,4 @@
 0x4d, 0x59, 0x4f, 0x79, 0x53, 0x65, 0x57, 0x75, 0x5b, 0x6d, 0x5f, 0x7d, 0x67, 0x73, 0x6f, 0x7b,
 0x00, 0x08, 0x14, 0x1c, 0x22, 0x2a, 0x36, 0x3e, 0x41, 0x49, 0x55, 0x5d, 0x63, 0x6b, 0x77, 0x7f,
 0x00,
-};
\ No newline at end of file
+};
diff --git a/media/libstagefright/codecs/aacenc/src/aacenc.c b/media/libstagefright/codecs/aacenc/src/aacenc.c
index b5e8a9c..ad2f29a 100644
--- a/media/libstagefright/codecs/aacenc/src/aacenc.c
+++ b/media/libstagefright/codecs/aacenc/src/aacenc.c
@@ -492,4 +492,4 @@
 	pDecHandle->Uninit = voAACEncUninit;
 
 	return VO_ERR_NONE;
-}
\ No newline at end of file
+}
diff --git a/media/libstagefright/codecs/aacenc/src/adj_thr.c b/media/libstagefright/codecs/aacenc/src/adj_thr.c
index c656f65..a8ab809 100644
--- a/media/libstagefright/codecs/aacenc/src/adj_thr.c
+++ b/media/libstagefright/codecs/aacenc/src/adj_thr.c
@@ -1039,7 +1039,7 @@
 
   /* minSnr adaptation */
   /* maximum reduction of minSnr goes down to minSnr^maxRed */
-  msaParam->maxRed = 0x20000000;     /* *0.25f /
+  msaParam->maxRed = 0x20000000;     /* *0.25f */
   /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
   msaParam->startRatio = 0x0ccccccd; /* 10 */
   /* maximum minSnr reduction to minSnr^maxRed is reached for
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/PrePostMDCT_v5.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/PrePostMDCT_v5.s
index 103cc91..da21d5f 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/PrePostMDCT_v5.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/PrePostMDCT_v5.s
@@ -128,4 +128,4 @@
 PostMDCT_END:
 	ldmia       sp!, {r4 - r11, pc}
 	@ENDP  @ |PostMDCT|
-	.end
\ No newline at end of file
+	.end
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/R4R8First_v5.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/R4R8First_v5.s
index 72cb9a3..4ca4f31 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/R4R8First_v5.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/R4R8First_v5.s
@@ -249,4 +249,4 @@
 	.word       0x5a82799a
 
 	@ENDP  @ |Radix8First|
-	.end
\ No newline at end of file
+	.end
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/Radix4FFT_v5.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/Radix4FFT_v5.s
index e81c82e..b59b967 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/Radix4FFT_v5.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/Radix4FFT_v5.s
@@ -166,4 +166,4 @@
 	ldmia   sp!, {r4 - r11, pc}
 
 	@ENDP  @ |Radix4FFT|
-	.end
\ No newline at end of file
+	.end
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s
index 64d767a..7f6b881 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s
@@ -23,9 +23,13 @@
 
 	.section .text
 	.global	PreMDCT
+	.fnstart
 
 PreMDCT:
 	stmdb     sp!, {r4 - r11, lr}
+	.save	  {r4 - r11, lr}
+	fstmfdd   sp!, {d8 - d15}
+	.vsave	  {d8 - d15}
 
 	add         r9, r0, r1, lsl #2
 	sub         r3, r9, #32
@@ -74,14 +78,20 @@
 	bne       	PreMDCT_LOOP
 
 PreMDCT_END:
+	fldmfdd   sp!, {d8 - d15}
 	ldmia     sp!, {r4 - r11, pc}
 	@ENDP  @ |PreMDCT|
+	.fnend
 
 	.section .text
 	.global	PostMDCT
+	.fnstart
 
 PostMDCT:
 	stmdb     sp!, {r4 - r11, lr}
+	.save	  {r4 - r11, lr}
+	fstmfdd   sp!, {d8 - d15}
+	.vsave	  {d8 - d15}
 
 	add         r9, r0, r1, lsl #2
 	sub         r3, r9, #32
@@ -129,7 +139,8 @@
 	bne       	PostMDCT_LOOP
 
 PostMDCT_END:
+	fldmfdd   sp!, {d8 - d15}
 	ldmia     sp!, {r4 - r11, pc}
 
 	@ENDP  		@ |PostMDCT|
-	.end
\ No newline at end of file
+	.fnend
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s
index 7fc5520..03fa6a9 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s
@@ -23,9 +23,13 @@
 
 	.section .text
 	.global	Radix8First
+	.fnstart
 
 Radix8First:
 	stmdb     		sp!, {r4 - r11, lr}
+	.save	  		{r4 - r11, lr}
+	fstmfdd   		sp!, {d8 - d15}
+	.vsave	  		{d8 - d15}
 
 	ldr       		r3, SQRT1_2
 	cmp       		r1, #0
@@ -103,17 +107,23 @@
 	bne       			Radix8First_LOOP
 
 Radix8First_END:
+	fldmfdd   sp!, {d8 - d15}
 	ldmia     sp!, {r4 - r11, pc}
 SQRT1_2:
 	.word      0x2d413ccd
 
 	@ENDP  @ |Radix8First|
+	.fnend
 
 	.section .text
 	.global	Radix4First
+	.fnstart
 
 Radix4First:
 	stmdb     	sp!, {r4 - r11, lr}
+	.save	  	{r4 - r11, lr}
+	fstmfdd   	sp!, {d8 - d15}
+	.vsave	  	{d8 - d15}
 
 	cmp       	r1, #0
 	beq       	Radix4First_END
@@ -140,7 +150,8 @@
 	bne       		Radix4First_LOOP
 
 Radix4First_END:
+	fldmfdd   		sp!, {d8 - d15}
 	ldmia    		sp!, {r4 - r11, pc}
 
 	@ENDP  @ |Radix4First|
-	.end
\ No newline at end of file
+	.fnend
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s
index b8655ae..431bc30 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s
@@ -23,9 +23,13 @@
 
 	.section .text
 	.global	Radix4FFT
+	.fnstart
 
 Radix4FFT:
 	stmdb    sp!, {r4 - r11, lr}
+	.save	 {r4 - r11, lr}
+	fstmfdd  sp!, {d8 - d15}
+	.vsave	 {d8 - d15}
 
 	mov			r1, r1, asr #2
 	cmp     	r1, #0
@@ -137,7 +141,8 @@
 	bne     			Radix4FFT_LOOP1
 
 Radix4FFT_END:
+	fldmfdd   			sp!, {d8 - d15}
 	ldmia   			sp!, {r4 - r11, pc}
 
 	@ENDP  @ |Radix4FFT|
-	.end
\ No newline at end of file
+	.fnend
diff --git a/media/libstagefright/codecs/aacenc/src/band_nrg.c b/media/libstagefright/codecs/aacenc/src/band_nrg.c
index 7501af1..e4034b8 100644
--- a/media/libstagefright/codecs/aacenc/src/band_nrg.c
+++ b/media/libstagefright/codecs/aacenc/src/band_nrg.c
@@ -99,4 +99,4 @@
   *bandEnergySideSum = accuSideSum;
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
index 3afbc4f..27d7e4d 100644
--- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
@@ -18,8 +18,8 @@
 
 #include "gsmamr_enc.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -210,7 +210,7 @@
     }
 
     MediaBuffer *buffer;
-    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
 
     uint8_t *outPtr = (uint8_t *)buffer->data();
 
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index b6aed81..94e8726 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -74,3 +74,30 @@
 LOCAL_MODULE := libstagefright_amrnbenc
 
 include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+        SoftAMRNBEncoder.cpp
+
+LOCAL_C_INCLUDES := \
+        frameworks/base/media/libstagefright/include \
+        frameworks/base/include/media/stagefright/openmax \
+        $(LOCAL_PATH)/src \
+        $(LOCAL_PATH)/include \
+        $(LOCAL_PATH)/../common/include \
+        $(LOCAL_PATH)/../common
+
+LOCAL_STATIC_LIBRARIES := \
+        libstagefright_amrnbenc
+
+LOCAL_SHARED_LIBRARIES := \
+        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_amrnb_common
+
+LOCAL_MODULE := libstagefright_soft_amrnbenc
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
new file mode 100644
index 0000000..07f8b4f
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2012 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 "SoftAMRNBEncoder"
+#include <utils/Log.h>
+
+#include "SoftAMRNBEncoder.h"
+
+#include "gsmamr_enc.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+
+namespace android {
+
+static const int32_t kSampleRate = 8000;
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftAMRNBEncoder::SoftAMRNBEncoder(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mEncState(NULL),
+      mSidState(NULL),
+      mBitRate(0),
+      mMode(MR475),
+      mInputSize(0),
+      mInputTimeUs(-1ll),
+      mSawInputEOS(false),
+      mSignalledError(false) {
+    initPorts();
+    CHECK_EQ(initEncoder(), (status_t)OK);
+}
+
+SoftAMRNBEncoder::~SoftAMRNBEncoder() {
+    if (mEncState != NULL) {
+        AMREncodeExit(&mEncState, &mSidState);
+        mEncState = mSidState = NULL;
+    }
+}
+
+void SoftAMRNBEncoder::initPorts() {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 8192;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/3gpp");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
+
+    addPort(def);
+}
+
+status_t SoftAMRNBEncoder::initEncoder() {
+    if (AMREncodeInit(&mEncState, &mSidState, false /* dtx_enable */) != 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+OMX_ERRORTYPE SoftAMRNBEncoder::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            formatParams->eEncoding =
+                (formatParams->nPortIndex == 0)
+                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAmr:
+        {
+            OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+                (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+            if (amrParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            amrParams->nChannels = 1;
+            amrParams->nBitRate = mBitRate;
+            amrParams->eAMRBandMode = (OMX_AUDIO_AMRBANDMODETYPE)(mMode + 1);
+            amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eEndian = OMX_EndianBig;
+            pcmParams->bInterleaved = OMX_TRUE;
+            pcmParams->nBitPerSample = 16;
+            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+
+            pcmParams->nChannels = 1;
+            pcmParams->nSamplingRate = kSampleRate;
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftAMRNBEncoder::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (strncmp((const char *)roleParams->cRole,
+                        "audio_encoder.amrnb",
+                        OMX_MAX_STRINGNAME_SIZE - 1)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPortFormat:
+        {
+            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            if ((formatParams->nPortIndex == 0
+                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+                || (formatParams->nPortIndex == 1
+                        && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAmr:
+        {
+            OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+                (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+            if (amrParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (amrParams->nChannels != 1
+                    || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
+                    || amrParams->eAMRFrameFormat
+                            != OMX_AUDIO_AMRFrameFormatFSF
+                    || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeNB0
+                    || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeNB7) {
+                return OMX_ErrorUndefined;
+            }
+
+            mBitRate = amrParams->nBitRate;
+            mMode = amrParams->eAMRBandMode - 1;
+
+            amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (pcmParams->nChannels != 1
+                    || pcmParams->nSamplingRate != kSampleRate) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+void SoftAMRNBEncoder::onQueueFilled(OMX_U32 portIndex) {
+    if (mSignalledError) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
+
+    for (;;) {
+        // We do the following until we run out of buffers.
+
+        while (mInputSize < numBytesPerInputFrame) {
+            // As long as there's still input data to be read we
+            // will drain "kNumSamplesPerFrame" samples
+            // into the "mInputFrame" buffer and then encode those
+            // as a unit into an output buffer.
+
+            if (mSawInputEOS || inQueue.empty()) {
+                return;
+            }
+
+            BufferInfo *inInfo = *inQueue.begin();
+            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+            const void *inData = inHeader->pBuffer + inHeader->nOffset;
+
+            size_t copy = numBytesPerInputFrame - mInputSize;
+            if (copy > inHeader->nFilledLen) {
+                copy = inHeader->nFilledLen;
+            }
+
+            if (mInputSize == 0) {
+                mInputTimeUs = inHeader->nTimeStamp;
+            }
+
+            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
+            mInputSize += copy;
+
+            inHeader->nOffset += copy;
+            inHeader->nFilledLen -= copy;
+
+            // "Time" on the input buffer has in effect advanced by the
+            // number of audio frames we just advanced nOffset by.
+            inHeader->nTimeStamp +=
+                (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
+
+            if (inHeader->nFilledLen == 0) {
+                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                    ALOGV("saw input EOS");
+                    mSawInputEOS = true;
+
+                    // Pad any remaining data with zeroes.
+                    memset((uint8_t *)mInputFrame + mInputSize,
+                           0,
+                           numBytesPerInputFrame - mInputSize);
+
+                    mInputSize = numBytesPerInputFrame;
+                }
+
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+
+                inData = NULL;
+                inHeader = NULL;
+                inInfo = NULL;
+            }
+        }
+
+        // At this  point we have all the input data necessary to encode
+        // a single frame, all we need is an output buffer to store the result
+        // in.
+
+        if (outQueue.empty()) {
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+        uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
+        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
+
+        Frame_Type_3GPP frameType;
+        int res = AMREncode(
+                mEncState, mSidState, (Mode)mMode,
+                mInputFrame, outPtr, &frameType, AMR_TX_WMF);
+
+        CHECK_GE(res, 0);
+        CHECK_LE((size_t)res, outAvailable);
+
+        // Convert header byte from WMF to IETF format.
+        outPtr[0] = ((outPtr[0] << 3) | 4) & 0x7c;
+
+        outHeader->nFilledLen = res;
+        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
+
+        if (mSawInputEOS) {
+            // We also tag this output buffer with EOS if it corresponds
+            // to the final input buffer.
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        }
+
+        outHeader->nTimeStamp = mInputTimeUs;
+
+#if 0
+        ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
+              nOutputBytes, mInputTimeUs, outHeader->nFlags);
+
+        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
+#endif
+
+        outQueue.erase(outQueue.begin());
+        outInfo->mOwnedByUs = false;
+        notifyFillBufferDone(outHeader);
+
+        outHeader = NULL;
+        outInfo = NULL;
+
+        mInputSize = 0;
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    return new android::SoftAMRNBEncoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h
new file mode 100644
index 0000000..50178c4
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 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 SOFT_AMRNB_ENCODER_H_
+
+#define SOFT_AMRNB_ENCODER_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+namespace android {
+
+struct SoftAMRNBEncoder : public SimpleSoftOMXComponent {
+    SoftAMRNBEncoder(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftAMRNBEncoder();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+    enum {
+        kNumBuffers             = 4,
+        kNumSamplesPerFrame     = 160,
+    };
+
+    void *mEncState;
+    void *mSidState;
+
+    OMX_U32 mBitRate;
+    int mMode;
+
+    size_t mInputSize;
+    int16_t mInputFrame[kNumSamplesPerFrame];
+    int64_t mInputTimeUs;
+
+    bool mSawInputEOS;
+    bool mSignalledError;
+
+    void initPorts();
+    status_t initEncoder();
+
+    status_t setAudioParams();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftAMRNBEncoder);
+};
+
+}  // namespace android
+
+#endif  // SOFT_AMRNB_ENCODER_H_
diff --git a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
index 60b1163..7fd3a95 100644
--- a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
@@ -22,8 +22,8 @@
 #include "voAMRWB.h"
 #include "cmnMemory.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -134,7 +134,7 @@
     // The largest buffer size is header + 477 bits
     mBufferGroup->add_buffer(new MediaBuffer(1024));
 
-    CHECK_EQ(OK, initCheck());
+    CHECK_EQ((status_t)OK, initCheck());
 
     mNumFramesOutput = 0;
 
@@ -163,7 +163,7 @@
     mBufferGroup = NULL;
 
 
-    CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+    CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
     mEncoderHandle = NULL;
 
     delete mApiHandle;
@@ -222,7 +222,7 @@
             }
 
             size_t align = mInputBuffer->range_length() % sizeof(int16_t);
-            CHECK_EQ(align, 0);
+            CHECK_EQ(align, (size_t)0);
 
             int64_t timeUs;
             if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
@@ -271,7 +271,7 @@
     CHECK(VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData));
 
     MediaBuffer *buffer;
-    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+    CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
     uint8_t *outPtr = (uint8_t *)buffer->data();
 
     VO_CODECBUFFER outputData;
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index ae43870..6ce6171 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -117,4 +117,26 @@
 
 include $(BUILD_STATIC_LIBRARY)
 
+################################################################################
 
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+        SoftAMRWBEncoder.cpp
+
+LOCAL_C_INCLUDES := \
+        frameworks/base/media/libstagefright/include \
+        frameworks/base/include/media/stagefright/openmax \
+	frameworks/base/media/libstagefright/codecs/common/include \
+
+LOCAL_STATIC_LIBRARIES := \
+        libstagefright_amrwbenc
+
+LOCAL_SHARED_LIBRARIES := \
+        libstagefright_omx libstagefright_foundation libutils \
+        libstagefright_enc_common
+
+LOCAL_MODULE := libstagefright_soft_amrwbenc
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
new file mode 100644
index 0000000..9ccb49c
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2012 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 "SoftAMRWBEncoder"
+#include <utils/Log.h>
+
+#include "SoftAMRWBEncoder.h"
+
+#include "cmnMemory.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+
+namespace android {
+
+static const int32_t kSampleRate = 16000;
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftAMRWBEncoder::SoftAMRWBEncoder(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mEncoderHandle(NULL),
+      mApiHandle(NULL),
+      mMemOperator(NULL),
+      mBitRate(0),
+      mMode(VOAMRWB_MD66),
+      mInputSize(0),
+      mInputTimeUs(-1ll),
+      mSawInputEOS(false),
+      mSignalledError(false) {
+    initPorts();
+    CHECK_EQ(initEncoder(), (status_t)OK);
+}
+
+SoftAMRWBEncoder::~SoftAMRWBEncoder() {
+    if (mEncoderHandle != NULL) {
+        CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+        mEncoderHandle = NULL;
+    }
+
+    delete mApiHandle;
+    mApiHandle = NULL;
+
+    delete mMemOperator;
+    mMemOperator = NULL;
+}
+
+void SoftAMRWBEncoder::initPorts() {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 8192;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/amr-wb");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
+
+    addPort(def);
+}
+
+status_t SoftAMRWBEncoder::initEncoder() {
+    mApiHandle = new VO_AUDIO_CODECAPI;
+
+    if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) {
+        ALOGE("Failed to get api handle");
+        return UNKNOWN_ERROR;
+    }
+
+    mMemOperator = new VO_MEM_OPERATOR;
+    mMemOperator->Alloc = cmnMemAlloc;
+    mMemOperator->Copy = cmnMemCopy;
+    mMemOperator->Free = cmnMemFree;
+    mMemOperator->Set = cmnMemSet;
+    mMemOperator->Check = cmnMemCheck;
+
+    VO_CODEC_INIT_USERDATA userData;
+    memset(&userData, 0, sizeof(userData));
+    userData.memflag = VO_IMF_USERMEMOPERATOR;
+    userData.memData = (VO_PTR) mMemOperator;
+
+    if (VO_ERR_NONE != mApiHandle->Init(
+                &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) {
+        ALOGE("Failed to init AMRWB encoder");
+        return UNKNOWN_ERROR;
+    }
+
+    VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267;
+    if (VO_ERR_NONE != mApiHandle->SetParam(
+                mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) {
+        ALOGE("Failed to set AMRWB encoder frame type to %d", type);
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+OMX_ERRORTYPE SoftAMRWBEncoder::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamAudioPortFormat:
+        {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            formatParams->eEncoding =
+                (formatParams->nPortIndex == 0)
+                    ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAmr:
+        {
+            OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+                (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+            if (amrParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            amrParams->nChannels = 1;
+            amrParams->nBitRate = mBitRate;
+
+            amrParams->eAMRBandMode =
+                (OMX_AUDIO_AMRBANDMODETYPE)(mMode + OMX_AUDIO_AMRBandModeWB0);
+
+            amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eEndian = OMX_EndianBig;
+            pcmParams->bInterleaved = OMX_TRUE;
+            pcmParams->nBitPerSample = 16;
+            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+
+            pcmParams->nChannels = 1;
+            pcmParams->nSamplingRate = kSampleRate;
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftAMRWBEncoder::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    switch (index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (strncmp((const char *)roleParams->cRole,
+                        "audio_encoder.amrwb",
+                        OMX_MAX_STRINGNAME_SIZE - 1)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPortFormat:
+        {
+            const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+                (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+            if (formatParams->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (formatParams->nIndex > 0) {
+                return OMX_ErrorNoMore;
+            }
+
+            if ((formatParams->nPortIndex == 0
+                        && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+                || (formatParams->nPortIndex == 1
+                        && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAmr:
+        {
+            OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+                (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+            if (amrParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (amrParams->nChannels != 1
+                    || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
+                    || amrParams->eAMRFrameFormat
+                            != OMX_AUDIO_AMRFrameFormatFSF
+                    || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeWB0
+                    || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeWB8) {
+                return OMX_ErrorUndefined;
+            }
+
+            mBitRate = amrParams->nBitRate;
+
+            mMode = (VOAMRWBMODE)(
+                    amrParams->eAMRBandMode - OMX_AUDIO_AMRBandModeWB0);
+
+            amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+            amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+            if (VO_ERR_NONE !=
+                    mApiHandle->SetParam(
+                        mEncoderHandle, VO_PID_AMRWB_MODE,  &mMode)) {
+                ALOGE("Failed to set AMRWB encoder mode to %d", mMode);
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (pcmParams->nChannels != 1
+                    || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+void SoftAMRWBEncoder::onQueueFilled(OMX_U32 portIndex) {
+    if (mSignalledError) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
+
+    for (;;) {
+        // We do the following until we run out of buffers.
+
+        while (mInputSize < numBytesPerInputFrame) {
+            // As long as there's still input data to be read we
+            // will drain "kNumSamplesPerFrame" samples
+            // into the "mInputFrame" buffer and then encode those
+            // as a unit into an output buffer.
+
+            if (mSawInputEOS || inQueue.empty()) {
+                return;
+            }
+
+            BufferInfo *inInfo = *inQueue.begin();
+            OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+            const void *inData = inHeader->pBuffer + inHeader->nOffset;
+
+            size_t copy = numBytesPerInputFrame - mInputSize;
+            if (copy > inHeader->nFilledLen) {
+                copy = inHeader->nFilledLen;
+            }
+
+            if (mInputSize == 0) {
+                mInputTimeUs = inHeader->nTimeStamp;
+            }
+
+            memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
+            mInputSize += copy;
+
+            inHeader->nOffset += copy;
+            inHeader->nFilledLen -= copy;
+
+            // "Time" on the input buffer has in effect advanced by the
+            // number of audio frames we just advanced nOffset by.
+            inHeader->nTimeStamp +=
+                (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
+
+            if (inHeader->nFilledLen == 0) {
+                if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                    ALOGV("saw input EOS");
+                    mSawInputEOS = true;
+
+                    // Pad any remaining data with zeroes.
+                    memset((uint8_t *)mInputFrame + mInputSize,
+                           0,
+                           numBytesPerInputFrame - mInputSize);
+
+                    mInputSize = numBytesPerInputFrame;
+                }
+
+                inQueue.erase(inQueue.begin());
+                inInfo->mOwnedByUs = false;
+                notifyEmptyBufferDone(inHeader);
+
+                inData = NULL;
+                inHeader = NULL;
+                inInfo = NULL;
+            }
+        }
+
+        // At this  point we have all the input data necessary to encode
+        // a single frame, all we need is an output buffer to store the result
+        // in.
+
+        if (outQueue.empty()) {
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+        uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
+        size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
+
+        VO_CODECBUFFER inputData;
+        memset(&inputData, 0, sizeof(inputData));
+        inputData.Buffer = (unsigned char *) mInputFrame;
+        inputData.Length = mInputSize;
+
+        CHECK_EQ(VO_ERR_NONE,
+                 mApiHandle->SetInputData(mEncoderHandle, &inputData));
+
+        VO_CODECBUFFER outputData;
+        memset(&outputData, 0, sizeof(outputData));
+        VO_AUDIO_OUTPUTINFO outputInfo;
+        memset(&outputInfo, 0, sizeof(outputInfo));
+
+        outputData.Buffer = outPtr;
+        outputData.Length = outAvailable;
+        VO_U32 ret = mApiHandle->GetOutputData(
+                mEncoderHandle, &outputData, &outputInfo);
+        CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL);
+
+        outHeader->nFilledLen = outputData.Length;
+        outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
+
+        if (mSawInputEOS) {
+            // We also tag this output buffer with EOS if it corresponds
+            // to the final input buffer.
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        }
+
+        outHeader->nTimeStamp = mInputTimeUs;
+
+#if 0
+        ALOGI("sending %ld bytes of data (time = %lld us, flags = 0x%08lx)",
+              outHeader->nFilledLen, mInputTimeUs, outHeader->nFlags);
+
+        hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
+#endif
+
+        outQueue.erase(outQueue.begin());
+        outInfo->mOwnedByUs = false;
+        notifyFillBufferDone(outHeader);
+
+        outHeader = NULL;
+        outInfo = NULL;
+
+        mInputSize = 0;
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    return new android::SoftAMRWBEncoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h
new file mode 100644
index 0000000..d0c1dab
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 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 SOFT_AMRWB_ENCODER_H_
+
+#define SOFT_AMRWB_ENCODER_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+#include "voAMRWB.h"
+
+struct VO_AUDIO_CODECAPI;
+struct VO_MEM_OPERATOR;
+
+namespace android {
+
+struct SoftAMRWBEncoder : public SimpleSoftOMXComponent {
+    SoftAMRWBEncoder(
+            const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftAMRWBEncoder();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+    enum {
+        kNumBuffers             = 4,
+        kNumSamplesPerFrame     = 320,
+    };
+
+    void *mEncoderHandle;
+    VO_AUDIO_CODECAPI *mApiHandle;
+    VO_MEM_OPERATOR *mMemOperator;
+
+    OMX_U32 mBitRate;
+    VOAMRWBMODE mMode;
+
+    size_t mInputSize;
+    int16_t mInputFrame[kNumSamplesPerFrame];
+    int64_t mInputTimeUs;
+
+    bool mSawInputEOS;
+    bool mSignalledError;
+
+    void initPorts();
+    status_t initEncoder();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftAMRWBEncoder);
+};
+
+}  // namespace android
+
+#endif  // SOFT_AMRWB_ENCODER_H_
diff --git a/media/libstagefright/codecs/amrwbenc/src/mem_align.c b/media/libstagefright/codecs/amrwbenc/src/mem_align.c
index a29baf3..3b7853f 100644
--- a/media/libstagefright/codecs/amrwbenc/src/mem_align.c
+++ b/media/libstagefright/codecs/amrwbenc/src/mem_align.c
@@ -23,6 +23,11 @@
 
 
 #include	"mem_align.h"
+#ifdef _MSC_VER
+#include	<stddef.h>
+#else
+#include	<stdint.h>
+#endif
 
 /*****************************************************************************
 *
@@ -66,8 +71,8 @@
 		pMemop->Set(CodecID, tmp, 0, size + alignment);
 
 		mem_ptr =
-			(unsigned char *) ((unsigned int) (tmp + alignment - 1) &
-					(~((unsigned int) (alignment - 1))));
+			(unsigned char *) ((intptr_t) (tmp + alignment - 1) &
+					(~((intptr_t) (alignment - 1))));
 
 		if (mem_ptr == tmp)
 			mem_ptr += alignment;
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index e202a2b..7533f07 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -24,8 +24,8 @@
 #include "avcenc_int.h"
 #include "OMX_Video.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -417,7 +417,7 @@
     *out = NULL;
 
     MediaBuffer *outputBuffer;
-    CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+    CHECK_EQ((status_t)OK, mGroup->acquire_buffer(&outputBuffer));
     uint8_t *outPtr = (uint8_t *) outputBuffer->data();
     uint32_t dataLength = outputBuffer->size();
 
@@ -557,9 +557,9 @@
     encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
     if (encoderStatus == AVCENC_SUCCESS) {
         outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
-        CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+        CHECK(NULL == PVAVCEncGetOverrunBuffer(mHandle));
     } else if (encoderStatus == AVCENC_PICTURE_READY) {
-        CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+        CHECK(NULL == PVAVCEncGetOverrunBuffer(mHandle));
         if (mIsIDRFrame) {
             outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
             mIsIDRFrame = 0;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
index d538603..20b0f8d 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -23,8 +23,8 @@
 #include "mp4enc_api.h"
 #include "OMX_Video.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -379,7 +379,7 @@
     *out = NULL;
 
     MediaBuffer *outputBuffer;
-    CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+    CHECK_EQ((status_t)OK, mGroup->acquire_buffer(&outputBuffer));
     uint8_t *outPtr = (uint8_t *) outputBuffer->data();
     int32_t dataLength = outputBuffer->size();
 
@@ -467,7 +467,7 @@
         mInputBuffer = NULL;
         return UNKNOWN_ERROR;
     }
-    CHECK_EQ(NULL, PVGetOverrunBuffer(mHandle));
+    CHECK(NULL == PVGetOverrunBuffer(mHandle));
     if (hintTrack.CodeType == 0) {  // I-frame serves as sync frame
         outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
     }
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 5cc3f78..597167f 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -18,8 +18,8 @@
 #define LOG_TAG "ColorConverter"
 #include <utils/Log.h>
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/ColorConverter.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaErrors.h>
 
 namespace android {
@@ -144,8 +144,8 @@
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_ptr = (const uint8_t *)src.mBits
         + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2;
@@ -182,11 +182,15 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[b2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_ptr += src.mWidth * 2;
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
@@ -290,15 +294,14 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((dst.mWidth & 3) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y =
         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
@@ -340,7 +343,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[r2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -349,7 +356,7 @@
             src_u += src.mWidth;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
@@ -361,15 +368,14 @@
 
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((dst.mWidth & 3) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y =
         (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
@@ -411,7 +417,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[r2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -420,7 +430,7 @@
             src_u += src.mWidth;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
@@ -430,15 +440,14 @@
         const BitmapParams &src, const BitmapParams &dst) {
     uint8_t *kAdjustedClip = initClip();
 
-    if (!((dst.mWidth & 3) == 0
-            && (src.mCropLeft & 1) == 0
+    if (!((src.mCropLeft & 1) == 0
             && src.cropWidth() == dst.cropWidth()
             && src.cropHeight() == dst.cropHeight())) {
         return ERROR_UNSUPPORTED;
     }
 
-    uint32_t *dst_ptr = (uint32_t *)dst.mBits
-        + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+    uint16_t *dst_ptr = (uint16_t *)dst.mBits
+        + dst.mCropTop * dst.mWidth + dst.mCropLeft;
 
     const uint8_t *src_y = (const uint8_t *)src.mBits;
 
@@ -478,7 +487,11 @@
                 | ((kAdjustedClip[g2] >> 2) << 5)
                 | (kAdjustedClip[b2] >> 3);
 
-            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+            if (x + 1 < src.cropWidth()) {
+                *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+            } else {
+                dst_ptr[x] = rgb1;
+            }
         }
 
         src_y += src.mWidth;
@@ -487,7 +500,7 @@
             src_u += src.mWidth;
         }
 
-        dst_ptr += dst.mWidth / 2;
+        dst_ptr += dst.mWidth;
     }
 
     return OK;
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 23c8e44..ff35d4a 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -16,7 +16,7 @@
 	testid3.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libutils libbinder
+	libstagefright libutils libbinder libstagefright_foundation
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_id3
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 6dde9d8..2e92926 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -20,8 +20,8 @@
 
 #include "../include/ID3.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 #include <byteswap.h>
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 0741045..bc4572c 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -23,7 +23,7 @@
 
 #include <binder/ProcessState.h>
 #include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 
 #define MAXPATHLEN 256
 
@@ -70,7 +70,7 @@
 
 void scanFile(const char *path) {
     sp<FileSource> file = new FileSource(path);
-    CHECK_EQ(file->initCheck(), OK);
+    CHECK_EQ(file->initCheck(), (status_t)OK);
 
     ID3 tag(file);
     if (!tag.isValid()) {
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 82c6476..4c7bfa6 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -41,7 +41,7 @@
 class DrmManagerClinet;
 class DecryptHandle;
 
-class TimedTextPlayer;
+class TimedTextDriver;
 struct WVMExtractor;
 
 struct AwesomeRenderer : public RefBase {
@@ -232,7 +232,7 @@
     sp<DecryptHandle> mDecryptHandle;
 
     int64_t mLastVideoTimeUs;
-    TimedTextPlayer *mTextPlayer;
+    TimedTextDriver *mTextDriver;
     mutable Mutex mTimedTextLock;
 
     sp<WVMExtractor> mWVMExtractor;
@@ -258,7 +258,7 @@
     void setVideoSource(sp<MediaSource> source);
     status_t initVideoDecoder(uint32_t flags = 0);
 
-    void addTextSource(sp<MediaSource> source);
+    void addTextSource(const sp<MediaSource>& source);
 
     void onStreamDone();
 
@@ -326,4 +326,3 @@
 }  // namespace android
 
 #endif  // AWESOME_PLAYER_H_
-
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index 53e764f..2c87b34 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -31,7 +31,7 @@
 public:
     OMX();
 
-    virtual bool livesLocally(pid_t pid);
+    virtual bool livesLocally(node_id node, pid_t pid);
 
     virtual status_t listNodes(List<ComponentInfo> *list);
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 4fbf47e..a0db719 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -93,7 +93,10 @@
 
     void advance();
     void reset();
-    void seek(int64_t seekTimeUs, bool seekToKeyFrame);
+
+    void seek(
+            int64_t seekTimeUs, bool seekToKeyFrame,
+            int64_t *actualFrameTimeUs);
 
     const mkvparser::Block *block() const;
     int64_t blockTimeUs() const;
@@ -303,22 +306,52 @@
     } while (!eos() && block()->GetTrackNumber() != mTrackNum);
 }
 
-void BlockIterator::seek(int64_t seekTimeUs, bool seekToKeyFrame) {
+void BlockIterator::seek(
+        int64_t seekTimeUs, bool seekToKeyFrame,
+        int64_t *actualFrameTimeUs) {
     Mutex::Autolock autoLock(mExtractor->mLock);
 
-    mCluster = mExtractor->mSegment->FindCluster(seekTimeUs * 1000ll);
+    *actualFrameTimeUs = -1ll;
+
+    int64_t seekTimeNs = seekTimeUs * 1000ll;
+
+    mCluster = mExtractor->mSegment->FindCluster(seekTimeNs);
     mBlockEntry = NULL;
     mBlockEntryIndex = 0;
 
-    do {
-        advance_l();
-    }
-    while (!eos() && block()->GetTrackNumber() != mTrackNum);
+    long prevKeyFrameBlockEntryIndex = -1;
 
-    if (seekToKeyFrame) {
-        while (!eos() && !mBlockEntry->GetBlock()->IsKey()) {
-            advance_l();
+    for (;;) {
+        advance_l();
+
+        if (eos()) {
+            break;
         }
+
+        if (block()->GetTrackNumber() != mTrackNum) {
+            continue;
+        }
+
+        if (block()->IsKey()) {
+            prevKeyFrameBlockEntryIndex = mBlockEntryIndex - 1;
+        }
+
+        int64_t timeNs = block()->GetTime(mCluster);
+
+        if (timeNs >= seekTimeNs) {
+            *actualFrameTimeUs = (timeNs + 500ll) / 1000ll;
+            break;
+        }
+    }
+
+    if (eos()) {
+        return;
+    }
+
+    if (seekToKeyFrame && !block()->IsKey()) {
+        CHECK_GE(prevKeyFrameBlockEntryIndex, 0);
+        mBlockEntryIndex = prevKeyFrameBlockEntryIndex;
+        advance_l();
     }
 }
 
@@ -397,6 +430,8 @@
         MediaBuffer **out, const ReadOptions *options) {
     *out = NULL;
 
+    int64_t targetSampleTimeUs = -1ll;
+
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
     if (options && options->getSeekTo(&seekTimeUs, &mode)
@@ -406,10 +441,14 @@
         // Apparently keyframe indication in audio tracks is unreliable,
         // fortunately in all our currently supported audio encodings every
         // frame is effectively a keyframe.
-        mBlockIter.seek(seekTimeUs, !mIsAudio);
+        int64_t actualFrameTimeUs;
+        mBlockIter.seek(seekTimeUs, !mIsAudio, &actualFrameTimeUs);
+
+        if (mode == ReadOptions::SEEK_CLOSEST) {
+            targetSampleTimeUs = actualFrameTimeUs;
+        }
     }
 
-again:
     while (mPendingFrames.empty()) {
         status_t err = readBlock();
 
@@ -424,6 +463,11 @@
     mPendingFrames.erase(mPendingFrames.begin());
 
     if (mType != AVC) {
+        if (targetSampleTimeUs >= 0ll) {
+            frame->meta_data()->setInt64(
+                    kKeyTargetTime, targetSampleTimeUs);
+        }
+
         *out = frame;
 
         return OK;
@@ -506,6 +550,11 @@
     frame->release();
     frame = NULL;
 
+    if (targetSampleTimeUs >= 0ll) {
+        buffer->meta_data()->setInt64(
+                kKeyTargetTime, targetSampleTimeUs);
+    }
+
     *out = buffer;
 
     return OK;
@@ -610,36 +659,41 @@
     return mIsLiveStreaming;
 }
 
-static void addESDSFromAudioSpecificInfo(
-        const sp<MetaData> &meta, const void *asi, size_t asiSize) {
+static void addESDSFromCodecPrivate(
+        const sp<MetaData> &meta,
+        bool isAudio, const void *priv, size_t privSize) {
     static const uint8_t kStaticESDS[] = {
         0x03, 22,
         0x00, 0x00,     // ES_ID
         0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
 
         0x04, 17,
-        0x40,                       // Audio ISO/IEC 14496-3
+        0x40,           // ObjectTypeIndication
         0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00,
 
         0x05,
-        // AudioSpecificInfo (with size prefix) follows
+        // CodecSpecificInfo (with size prefix) follows
     };
 
     // Make sure all sizes can be coded in a single byte.
-    CHECK(asiSize + 22 - 2 < 128);
-    size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1;
+    CHECK(privSize + 22 - 2 < 128);
+    size_t esdsSize = sizeof(kStaticESDS) + privSize + 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);
+    *ptr++ = privSize;
+    memcpy(ptr, priv, privSize);
 
     // Increment by codecPrivateSize less 2 bytes that are accounted for
     // already in lengths of 22/17
-    esds[1] += asiSize - 2;
-    esds[6] += asiSize - 2;
+    esds[1] += privSize - 2;
+    esds[6] += privSize - 2;
+
+    // Set ObjectTypeIndication.
+    esds[7] = isAudio ? 0x40   // Audio ISO/IEC 14496-3
+                      : 0x20;  // Visual ISO/IEC 14496-2
 
     meta->setData(kKeyESDS, 0, esds, esdsSize);
 
@@ -707,9 +761,21 @@
                 if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
                     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
                     meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
+                } else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) {
+                    if (codecPrivateSize > 0) {
+                        meta->setCString(
+                                kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+                        addESDSFromCodecPrivate(
+                                meta, false, codecPrivate, codecPrivateSize);
+                    } else {
+                        ALOGW("%s is detected, but does not have configuration.",
+                                codecID);
+                        continue;
+                    }
                 } else if (!strcmp("V_VP8", codecID)) {
                     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VPX);
                 } else {
+                    ALOGW("%s is not supported.", codecID);
                     continue;
                 }
 
@@ -727,13 +793,16 @@
                     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
                     CHECK(codecPrivateSize >= 2);
 
-                    addESDSFromAudioSpecificInfo(
-                            meta, codecPrivate, codecPrivateSize);
+                    addESDSFromCodecPrivate(
+                            meta, true, codecPrivate, codecPrivateSize);
                 } else if (!strcmp("A_VORBIS", codecID)) {
                     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
 
                     addVorbisCodecInfo(meta, codecPrivate, codecPrivateSize);
+                } else if (!strcmp("A_MPEG/L3", codecID)) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
                 } else {
+                    ALOGW("%s is not supported.", codecID);
                     continue;
                 }
 
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 03033f5..e1589b4 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -22,8 +22,8 @@
 #include "include/LiveSession.h"
 #include "include/NuCachedSource2.h"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 694b12d8..f11fcd2 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -25,7 +25,7 @@
 #include "../include/OMXNodeInstance.h"
 
 #include <binder/IMemory.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <utils/threads.h>
 
 #include "OMXMaster.h"
@@ -102,7 +102,7 @@
     if (status != WOULD_BLOCK) {
         // Other than join to self, the only other error return codes are
         // whatever readyToRun() returns, and we don't override that
-        CHECK_EQ(status, NO_ERROR);
+        CHECK_EQ(status, (status_t)NO_ERROR);
     }
 }
 
@@ -185,7 +185,7 @@
     instance->onObserverDied(mMaster);
 }
 
-bool OMX::livesLocally(pid_t pid) {
+bool OMX::livesLocally(node_id node, pid_t pid) {
     return pid == getpid();
 }
 
diff --git a/media/libstagefright/omx/OMXComponentBase.cpp b/media/libstagefright/omx/OMXComponentBase.cpp
index 35227a0..7d11dce 100644
--- a/media/libstagefright/omx/OMXComponentBase.cpp
+++ b/media/libstagefright/omx/OMXComponentBase.cpp
@@ -18,7 +18,7 @@
 
 #include <stdlib.h>
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
 
@@ -33,7 +33,7 @@
 OMXComponentBase::~OMXComponentBase() {}
 
 void OMXComponentBase::setComponentHandle(OMX_COMPONENTTYPE *handle) {
-    CHECK_EQ(mComponentHandle, NULL);
+    CHECK(mComponentHandle == NULL);
     mComponentHandle = handle;
 }
 
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index d698939..6b6d0ab 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -24,7 +24,7 @@
 
 #include <dlfcn.h>
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
 
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 8938e33..099c4f5 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -24,8 +24,8 @@
 #include <OMX_Component.h>
 
 #include <binder/IMemory.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/HardwareAPI.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaErrors.h>
 
 namespace android {
@@ -91,11 +91,11 @@
 }
 
 OMXNodeInstance::~OMXNodeInstance() {
-    CHECK_EQ(mHandle, NULL);
+    CHECK(mHandle == NULL);
 }
 
 void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
-    CHECK_EQ(mHandle, NULL);
+    CHECK(mHandle == NULL);
     mNodeID = node_id;
     mHandle = handle;
 }
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 0914f32..c79e01f 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -333,8 +333,9 @@
 
 void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
     Mutex::Autolock autoLock(mLock);
-
-    switch (msg->what()) {
+    uint32_t msgType = msg->what();
+    ALOGV("msgType = %d", msgType);
+    switch (msgType) {
         case kWhatSendCommand:
         {
             int32_t cmd, param;
@@ -354,27 +355,27 @@
             CHECK(mState == OMX_StateExecuting && mTargetState == mState);
 
             bool found = false;
-            for (size_t i = 0; i < mPorts.size(); ++i) {
-                PortInfo *port = &mPorts.editItemAt(i);
+            size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
+                    header->nInputPortIndex: header->nOutputPortIndex;
+            PortInfo *port = &mPorts.editItemAt(portIndex);
 
-                for (size_t j = 0; j < port->mBuffers.size(); ++j) {
-                    BufferInfo *buffer = &port->mBuffers.editItemAt(j);
+            for (size_t j = 0; j < port->mBuffers.size(); ++j) {
+                BufferInfo *buffer = &port->mBuffers.editItemAt(j);
 
-                    if (buffer->mHeader == header) {
-                        CHECK(!buffer->mOwnedByUs);
+                if (buffer->mHeader == header) {
+                    CHECK(!buffer->mOwnedByUs);
 
-                        buffer->mOwnedByUs = true;
+                    buffer->mOwnedByUs = true;
 
-                        CHECK((msg->what() == kWhatEmptyThisBuffer
-                                    && port->mDef.eDir == OMX_DirInput)
-                                || (port->mDef.eDir == OMX_DirOutput));
+                    CHECK((msgType == kWhatEmptyThisBuffer
+                            && port->mDef.eDir == OMX_DirInput)
+                            || (port->mDef.eDir == OMX_DirOutput));
 
-                        port->mQueue.push_back(buffer);
-                        onQueueFilled(i);
+                    port->mQueue.push_back(buffer);
+                    onQueueFilled(portIndex);
 
-                        found = true;
-                        break;
-                    }
+                    found = true;
+                    break;
                 }
             }
 
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index da3ae42..99ffe7d 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -35,8 +35,11 @@
 
 } kComponents[] = {
     { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
+    { "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" },
     { "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },
+    { "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" },
     { "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },
+    { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" },
     { "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" },
     { "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },
     { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index bf69428..0c0a70c 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -5,13 +5,15 @@
 	OMXHarness.cpp  \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libbinder libmedia libutils
+	libstagefright libbinder libmedia libutils libstagefright_foundation
 
-LOCAL_C_INCLUDES:= \
+LOCAL_C_INCLUDES := \
 	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/base/include/media/stagefright/openmax
 
-LOCAL_MODULE:= omx_tests
+LOCAL_MODULE := omx_tests
+
+LOCAL_MODULE_TAGS := tests
 
 include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 8faf544..fab1771 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -26,9 +26,9 @@
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
 #include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
 #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/MediaExtractor.h>
@@ -155,7 +155,7 @@
         if (err == TIMED_OUT) {
             return err;
         }
-        CHECK_EQ(err, OK);
+        CHECK_EQ(err, (status_t)OK);
     }
 }
 
@@ -317,7 +317,7 @@
     EXPECT_SUCCESS(err, "allocatePortBuffers(input)");
 
     err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
-    CHECK_EQ(err, TIMED_OUT);
+    CHECK_EQ(err, (status_t)TIMED_OUT);
 
     Vector<Buffer> outputBuffers;
     err = allocatePortBuffers(dealer, node, 1, &outputBuffers);
@@ -412,7 +412,7 @@
     // Make sure node doesn't just transition to loaded before we are done
     // freeing all input and output buffers.
     err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
-    CHECK_EQ(err, TIMED_OUT);
+    CHECK_EQ(err, (status_t)TIMED_OUT);
 
     for (size_t i = 0; i < inputBuffers.size(); ++i) {
         err = mOMX->freeBuffer(node, 0, inputBuffers[i].mID);
@@ -420,7 +420,7 @@
     }
 
     err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
-    CHECK_EQ(err, TIMED_OUT);
+    CHECK_EQ(err, (status_t)TIMED_OUT);
 
     for (size_t i = 0; i < outputBuffers.size(); ++i) {
         err = mOMX->freeBuffer(node, 1, outputBuffers[i].mID);
@@ -584,7 +584,7 @@
         return UNKNOWN_ERROR;
     }
 
-    CHECK_EQ(seekSource->start(), OK);
+    CHECK_EQ(seekSource->start(), (status_t)OK);
 
     sp<MediaSource> codec = OMXCodec::Create(
             mOMX, source->getFormat(), false /* createEncoder */,
@@ -592,7 +592,7 @@
 
     CHECK(codec != NULL);
 
-    CHECK_EQ(codec->start(), OK);
+    CHECK_EQ(codec->start(), (status_t)OK);
 
     int64_t durationUs;
     CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs));
@@ -638,7 +638,7 @@
                     requestedSeekTimeUs, MediaSource::ReadOptions::SEEK_NEXT_SYNC);
 
             if (seekSource->read(&buffer, &options) != OK) {
-                CHECK_EQ(buffer, NULL);
+                CHECK(buffer == NULL);
                 actualSeekTimeUs = -1;
             } else {
                 CHECK(buffer != NULL);
@@ -659,7 +659,7 @@
             err = codec->read(&buffer, &options);
             options.clearSeekTo();
             if (err == INFO_FORMAT_CHANGED) {
-                CHECK_EQ(buffer, NULL);
+                CHECK(buffer == NULL);
                 continue;
             }
             if (err == OK) {
@@ -670,7 +670,7 @@
                     continue;
                 }
             } else {
-                CHECK_EQ(buffer, NULL);
+                CHECK(buffer == NULL);
             }
 
             break;
@@ -679,7 +679,7 @@
         if (requestedSeekTimeUs < 0) {
             // Linear read.
             if (err != OK) {
-                CHECK_EQ(buffer, NULL);
+                CHECK(buffer == NULL);
             } else {
                 CHECK(buffer != NULL);
                 buffer->release();
@@ -694,8 +694,8 @@
                    "We attempted to seek beyond EOS and expected "
                    "ERROR_END_OF_STREAM to be returned, but instead "
                    "we found some other error.");
-            CHECK_EQ(err, ERROR_END_OF_STREAM);
-            CHECK_EQ(buffer, NULL);
+            CHECK_EQ(err, (status_t)ERROR_END_OF_STREAM);
+            CHECK(buffer == NULL);
         } else {
             EXPECT(err == OK,
                    "Expected a valid buffer to be returned from "
@@ -715,7 +715,7 @@
                 buffer->release();
                 buffer = NULL;
 
-                CHECK_EQ(codec->stop(), OK);
+                CHECK_EQ(codec->stop(), (status_t)OK);
 
                 return UNKNOWN_ERROR;
             }
@@ -725,7 +725,7 @@
         }
     }
 
-    CHECK_EQ(codec->stop(), OK);
+    CHECK_EQ(codec->stop(), (status_t)OK);
 
     return OK;
 }
@@ -841,7 +841,7 @@
     srand(seed);
 
     sp<Harness> h = new Harness;
-    CHECK_EQ(h->initCheck(), OK);
+    CHECK_EQ(h->initCheck(), (status_t)OK);
 
     if (argc == 0) {
         h->testAll();
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 76b507f..d7cec04 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -35,7 +35,7 @@
 #include <binder/ProcessState.h>
 #include <ui/FramebufferNativeWindow.h>
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
@@ -475,7 +475,7 @@
     mr->setVideoFrameRate(fps);
     mr->prepare();
     ALOGV("Starting MediaRecorder...");
-    CHECK_EQ(OK, mr->start());
+    CHECK_EQ((status_t)OK, mr->start());
     return mr;
 }
 
@@ -757,7 +757,7 @@
 
     ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU));
     ALOGV("Stopping MediaRecorder...");
-    CHECK_EQ(OK, mr->stop());
+    CHECK_EQ((status_t)OK, mr->stop());
     mr.clear();
     close(fd);
 }
@@ -886,7 +886,7 @@
     mEglSurface = EGL_NO_SURFACE;
 
     ALOGV("Stopping MediaRecorder...");
-    CHECK_EQ(OK, mr->stop());
+    CHECK_EQ((status_t)OK, mr->stop());
     mr.clear();
     close(fd);
 }
@@ -929,7 +929,7 @@
     mEglSurface = EGL_NO_SURFACE;
 
     ALOGV("Stopping MediaRecorder...");
-    CHECK_EQ(OK, mr->stop());
+    CHECK_EQ((status_t)OK, mr->stop());
     mr.clear();
     close(fd);
 }
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index 59d0e15..8b23dee 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -3,7 +3,10 @@
 
 LOCAL_SRC_FILES:=                 \
         TextDescriptions.cpp      \
-        TimedTextParser.cpp       \
+        TimedTextDriver.cpp       \
+        TimedTextInBandSource.cpp \
+        TimedTextSource.cpp       \
+        TimedTextSRTSource.cpp    \
         TimedTextPlayer.cpp
 
 LOCAL_CFLAGS += -Wno-multichar
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
new file mode 100644
index 0000000..9ec9415
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -0,0 +1,223 @@
+ /*
+ * Copyright (C) 2012 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 "TimedTextDriver"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+#include "TimedTextDriver.h"
+
+#include "TextDescriptions.h"
+#include "TimedTextPlayer.h"
+#include "TimedTextSource.h"
+
+namespace android {
+
+TimedTextDriver::TimedTextDriver(
+        const wp<MediaPlayerBase> &listener)
+    : mLooper(new ALooper),
+      mListener(listener),
+      mState(UNINITIALIZED) {
+    mLooper->setName("TimedTextDriver");
+    mLooper->start();
+    mPlayer = new TimedTextPlayer(listener);
+    mLooper->registerHandler(mPlayer);
+}
+
+TimedTextDriver::~TimedTextDriver() {
+    mTextInBandVector.clear();
+    mTextOutOfBandVector.clear();
+    mLooper->stop();
+}
+
+status_t TimedTextDriver::setTimedTextTrackIndex_l(int32_t index) {
+    if (index >=
+            (int)(mTextInBandVector.size() + mTextOutOfBandVector.size())) {
+        return BAD_VALUE;
+    }
+
+    sp<TimedTextSource> source;
+    if (index < mTextInBandVector.size()) {
+        source = mTextInBandVector.itemAt(index);
+    } else {
+        source = mTextOutOfBandVector.itemAt(index - mTextInBandVector.size());
+    }
+    mPlayer->setDataSource(source);
+    return OK;
+}
+
+status_t TimedTextDriver::start() {
+    Mutex::Autolock autoLock(mLock);
+    switch (mState) {
+        case UNINITIALIZED:
+            return INVALID_OPERATION;
+        case STOPPED:
+            mPlayer->start();
+            break;
+        case PLAYING:
+            return OK;
+        case PAUSED:
+            mPlayer->resume();
+            break;
+        default:
+            TRESPASS();
+    }
+    mState = PLAYING;
+    return OK;
+}
+
+status_t TimedTextDriver::stop() {
+    return pause();
+}
+
+// TODO: Test if pause() works properly.
+// Scenario 1: start - pause - resume
+// Scenario 2: start - seek
+// Scenario 3: start - pause - seek - resume
+status_t TimedTextDriver::pause() {
+    Mutex::Autolock autoLock(mLock);
+    switch (mState) {
+        case UNINITIALIZED:
+            return INVALID_OPERATION;
+        case STOPPED:
+            return OK;
+        case PLAYING:
+            mPlayer->pause();
+            break;
+        case PAUSED:
+            return OK;
+        default:
+            TRESPASS();
+    }
+    mState = PAUSED;
+    return OK;
+}
+
+status_t TimedTextDriver::resume() {
+    return start();
+}
+
+status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
+    mPlayer->seekToAsync(timeUs);
+    return OK;
+}
+
+status_t TimedTextDriver::setTimedTextTrackIndex(int32_t index) {
+    // TODO: This is current implementation for MediaPlayer::disableTimedText().
+    // Find better way for readability.
+    if (index < 0) {
+        mPlayer->pause();
+        return OK;
+    }
+
+    status_t ret = OK;
+    Mutex::Autolock autoLock(mLock);
+    switch (mState) {
+        case UNINITIALIZED:
+            ret = INVALID_OPERATION;
+            break;
+        case PAUSED:
+            ret = setTimedTextTrackIndex_l(index);
+            break;
+        case PLAYING:
+            mPlayer->pause();
+            ret = setTimedTextTrackIndex_l(index);
+            if (ret != OK) {
+                break;
+            }
+            mPlayer->start();
+            break;
+        case STOPPED:
+            // TODO: The only difference between STOPPED and PAUSED is this
+            // part. Revise the flow from "MediaPlayer::enableTimedText()" and
+            // remove one of the status, PAUSED and STOPPED, if possible.
+            ret = setTimedTextTrackIndex_l(index);
+            if (ret != OK) {
+                break;
+            }
+            mPlayer->start();
+            break;
+        defaut:
+            TRESPASS();
+    }
+    return ret;
+}
+
+status_t TimedTextDriver::addInBandTextSource(
+        const sp<MediaSource>& mediaSource) {
+    sp<TimedTextSource> source =
+            TimedTextSource::CreateTimedTextSource(mediaSource);
+    if (source == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+    Mutex::Autolock autoLock(mLock);
+    mTextInBandVector.add(source);
+    if (mState == UNINITIALIZED) {
+        mState = STOPPED;
+    }
+    return OK;
+}
+
+status_t TimedTextDriver::addOutOfBandTextSource(
+        const Parcel &request) {
+    // TODO: Define "TimedTextSource::CreateFromURI(uri)"
+    // and move below lines there..?
+
+    // String values written in Parcel are UTF-16 values.
+    const String16 uri16 = request.readString16();
+    String8 uri = String8(request.readString16());
+
+    uri.toLower();
+    // To support local subtitle file only for now
+    if (strncasecmp("file://", uri.string(), 7)) {
+        return ERROR_UNSUPPORTED;
+    }
+    sp<DataSource> dataSource =
+            DataSource::CreateFromURI(uri);
+    if (dataSource == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    sp<TimedTextSource> source;
+    if (uri.getPathExtension() == String8(".srt")) {
+        source = TimedTextSource::CreateTimedTextSource(
+                dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
+    }
+
+    if (source == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+
+    mTextOutOfBandVector.add(source);
+    if (mState == UNINITIALIZED) {
+        mState = STOPPED;
+    }
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextDriver.h b/media/libstagefright/timedtext/TimedTextDriver.h
new file mode 100644
index 0000000..efedb6e
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextDriver.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 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 TIMED_TEXT_DRIVER_H_
+#define TIMED_TEXT_DRIVER_H_
+
+#include <media/stagefright/foundation/ABase.h> // for DISALLOW_* macro
+#include <utils/Errors.h> // for status_t
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class ALooper;
+class MediaPlayerBase;
+class MediaSource;
+class Parcel;
+class TimedTextPlayer;
+class TimedTextSource;
+
+class TimedTextDriver {
+public:
+    TimedTextDriver(const wp<MediaPlayerBase> &listener);
+
+    ~TimedTextDriver();
+
+    // TODO: pause-resume pair seems equivalent to stop-start pair.
+    // Check if it is replaceable with stop-start.
+    status_t start();
+    status_t stop();
+    status_t pause();
+    status_t resume();
+
+    status_t seekToAsync(int64_t timeUs);
+
+    status_t addInBandTextSource(const sp<MediaSource>& source);
+    status_t addOutOfBandTextSource(const Parcel &request);
+
+    status_t setTimedTextTrackIndex(int32_t index);
+
+private:
+    Mutex mLock;
+
+    enum State {
+        UNINITIALIZED,
+        STOPPED,
+        PLAYING,
+        PAUSED,
+    };
+
+    sp<ALooper> mLooper;
+    sp<TimedTextPlayer> mPlayer;
+    wp<MediaPlayerBase> mListener;
+
+    // Variables to be guarded by mLock.
+    State mState;
+    Vector<sp<TimedTextSource> > mTextInBandVector;
+    Vector<sp<TimedTextSource> > mTextOutOfBandVector;
+    // -- End of variables to be guarded by mLock
+
+    status_t setTimedTextTrackIndex_l(int32_t index);
+
+    DISALLOW_EVIL_CONSTRUCTORS(TimedTextDriver);
+};
+
+}  // namespace android
+
+#endif  // TIMED_TEXT_DRIVER_H_
diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.cpp b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
new file mode 100644
index 0000000..afb73fb5
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
@@ -0,0 +1,118 @@
+ /*
+ * Copyright (C) 2012 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 "TimedTextInBandSource"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/ADebug.h>  // CHECK_XX macro
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>  // for MEDIA_MIMETYPE_xxx
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+#include "TimedTextInBandSource.h"
+#include "TextDescriptions.h"
+
+namespace android {
+
+TimedTextInBandSource::TimedTextInBandSource(const sp<MediaSource>& mediaSource)
+    : mSource(mediaSource) {
+}
+
+TimedTextInBandSource::~TimedTextInBandSource() {
+}
+
+status_t TimedTextInBandSource::read(
+        int64_t *timeUs, Parcel *parcel, const MediaSource::ReadOptions *options) {
+    MediaBuffer *textBuffer = NULL;
+    status_t err = mSource->read(&textBuffer, options);
+    if (err != OK) {
+        return err;
+    }
+    CHECK(textBuffer != NULL);
+    textBuffer->meta_data()->findInt64(kKeyTime, timeUs);
+    // TODO: this is legacy code. when 'timeUs' can be <= 0?
+    if (*timeUs > 0) {
+        extractAndAppendLocalDescriptions(*timeUs, textBuffer, parcel);
+    }
+    textBuffer->release();
+    return OK;
+}
+
+// Each text sample consists of a string of text, optionally with sample
+// modifier description. The modifier description could specify a new
+// text style for the string of text. These descriptions are present only
+// if they are needed. This method is used to extract the modifier
+// description and append it at the end of the text.
+status_t TimedTextInBandSource::extractAndAppendLocalDescriptions(
+        int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel) {
+    const void *data;
+    size_t size = 0;
+    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
+
+    const char *mime;
+    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+    if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) {
+        data = textBuffer->data();
+        size = textBuffer->size();
+
+        if (size > 0) {
+            parcel->freeData();
+            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+            return TextDescriptions::getParcelOfDescriptions(
+                    (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
+        }
+        return OK;
+    }
+    return ERROR_UNSUPPORTED;
+}
+
+// To extract and send the global text descriptions for all the text samples
+// in the text track or text file.
+// TODO: send error message to application via notifyListener()...?
+status_t TimedTextInBandSource::extractGlobalDescriptions(Parcel *parcel) {
+    const void *data;
+    size_t size = 0;
+    int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS;
+
+    const char *mime;
+    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+    // support 3GPP only for now
+    if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) {
+        uint32_t type;
+        // get the 'tx3g' box content. This box contains the text descriptions
+        // used to render the text track
+        if (!mSource->getFormat()->findData(
+                kKeyTextFormatData, &type, &data, &size)) {
+            return ERROR_MALFORMED;
+        }
+
+        if (size > 0) {
+            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+            return TextDescriptions::getParcelOfDescriptions(
+                    (const uint8_t *)data, size, flag, 0, parcel);
+        }
+        return OK;
+    }
+    return ERROR_UNSUPPORTED;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.h b/media/libstagefright/timedtext/TimedTextInBandSource.h
new file mode 100644
index 0000000..26e5737
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextInBandSource.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 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 TIMED_TEXT_IN_BAND_SOURCE_H_
+#define TIMED_TEXT_IN_BAND_SOURCE_H_
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+
+#include "TimedTextSource.h"
+
+namespace android {
+
+class MediaBuffer;
+class Parcel;
+
+class TimedTextInBandSource : public TimedTextSource {
+ public:
+  TimedTextInBandSource(const sp<MediaSource>& mediaSource);
+  virtual status_t start() { return mSource->start(); }
+  virtual status_t stop() { return mSource->stop(); }
+  virtual status_t read(
+          int64_t *timeUs,
+          Parcel *parcel,
+          const MediaSource::ReadOptions *options = NULL);
+  virtual status_t extractGlobalDescriptions(Parcel *parcel);
+
+ protected:
+  virtual ~TimedTextInBandSource();
+
+ private:
+  sp<MediaSource> mSource;
+
+  status_t extractAndAppendLocalDescriptions(
+        int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel);
+
+  DISALLOW_EVIL_CONSTRUCTORS(TimedTextInBandSource);
+};
+
+}  // namespace android
+
+#endif  // TIMED_TEXT_IN_BAND_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextParser.cpp b/media/libstagefright/timedtext/TimedTextParser.cpp
deleted file mode 100644
index caea0a4..0000000
--- a/media/libstagefright/timedtext/TimedTextParser.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "TimedTextParser.h"
-#include <media/stagefright/DataSource.h>
-
-namespace android {
-
-TimedTextParser::TimedTextParser()
-    : mDataSource(NULL),
-      mOffset(0),
-      mIndex(0) {
-}
-
-TimedTextParser::~TimedTextParser() {
-    reset();
-}
-
-status_t TimedTextParser::init(
-        const sp<DataSource> &dataSource, FileType fileType) {
-    mDataSource = dataSource;
-    mFileType = fileType;
-
-    status_t err;
-    if ((err = scanFile()) != OK) {
-        reset();
-        return err;
-    }
-
-    return OK;
-}
-
-void TimedTextParser::reset() {
-    mDataSource.clear();
-    mTextVector.clear();
-    mOffset = 0;
-    mIndex = 0;
-}
-
-// scan the text file to get start/stop time and the
-// offset of each piece of text content
-status_t TimedTextParser::scanFile() {
-    if (mFileType != OUT_OF_BAND_FILE_SRT) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    off64_t offset = 0;
-    int64_t startTimeUs;
-    bool endOfFile = false;
-
-    while (!endOfFile) {
-        TextInfo info;
-        status_t err = getNextInSrtFileFormat(&offset, &startTimeUs, &info);
-
-        if (err != OK) {
-            if (err == ERROR_END_OF_STREAM) {
-                endOfFile = true;
-            } else {
-                return err;
-            }
-        } else {
-            mTextVector.add(startTimeUs, info);
-        }
-    }
-
-    if (mTextVector.isEmpty()) {
-        return ERROR_MALFORMED;
-    }
-    return OK;
-}
-
-// read one line started from *offset and store it into data.
-status_t TimedTextParser::readNextLine(off64_t *offset, AString *data) {
-    char character;
-
-    data->clear();
-
-    while (true) {
-        ssize_t err;
-        if ((err = mDataSource->readAt(*offset, &character, 1)) < 1) {
-            if (err == 0) {
-                return ERROR_END_OF_STREAM;
-            }
-            return ERROR_IO;
-        }
-
-        (*offset) ++;
-
-        // a line could end with CR, LF or CR + LF
-        if (character == 10) {
-            break;
-        } else if (character == 13) {
-            if ((err = mDataSource->readAt(*offset, &character, 1)) < 1) {
-                if (err == 0) { // end of the stream
-                    return OK;
-                }
-                return ERROR_IO;
-            }
-
-            (*offset) ++;
-
-            if (character != 10) {
-                (*offset) --;
-            }
-            break;
-        }
-
-        data->append(character);
-    }
-
-    return OK;
-}
-
-/* SRT format:
- *  Subtitle number
- *  Start time --> End time
- *  Text of subtitle (one or more lines)
- *  Blank lines
- *
- * .srt file example:
- *  1
- *  00:00:20,000 --> 00:00:24,400
- *  Altocumulus clouds occur between six thousand
- *
- *  2
- *  00:00:24,600 --> 00:00:27,800
- *  and twenty thousand feet above ground level.
- */
-status_t TimedTextParser::getNextInSrtFileFormat(
-        off64_t *offset, int64_t *startTimeUs, TextInfo *info) {
-    AString data;
-    status_t err;
-
-    // To skip blank lines.
-    do {
-        if ((err = readNextLine(offset, &data)) != OK) {
-            return err;
-        }
-        data.trim();
-    } while(data.empty());
-
-    // Just ignore the first non-blank line which is subtitle sequence number.
-
-    if ((err = readNextLine(offset, &data)) != OK) {
-        return err;
-    }
-    int hour1, hour2, min1, min2, sec1, sec2, msec1, msec2;
-    // the start time format is: hours:minutes:seconds,milliseconds
-    // 00:00:24,600 --> 00:00:27,800
-    if (sscanf(data.c_str(), "%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d",
-                &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) {
-        return ERROR_MALFORMED;
-    }
-
-    *startTimeUs = ((hour1 * 3600 + min1 * 60 + sec1) * 1000 + msec1) * 1000ll;
-    info->endTimeUs = ((hour2 * 3600 + min2 * 60 + sec2) * 1000 + msec2) * 1000ll;
-    if (info->endTimeUs <= *startTimeUs) {
-        return ERROR_MALFORMED;
-    }
-
-    info->offset = *offset;
-
-    bool needMoreData = true;
-    while (needMoreData) {
-        if ((err = readNextLine(offset, &data)) != OK) {
-            if (err == ERROR_END_OF_STREAM) {
-                needMoreData = false;
-            } else {
-                return err;
-            }
-        }
-
-        if (needMoreData) {
-            data.trim();
-            if (data.empty()) {
-                // it's an empty line used to separate two subtitles
-                needMoreData = false;
-            }
-        }
-    }
-
-    info->textLen = *offset - info->offset;
-
-    return OK;
-}
-
-status_t TimedTextParser::getText(
-        AString *text, int64_t *startTimeUs, int64_t *endTimeUs,
-        const MediaSource::ReadOptions *options) {
-    Mutex::Autolock autoLock(mLock);
-
-    text->clear();
-
-    int64_t seekTimeUs;
-    MediaSource::ReadOptions::SeekMode mode;
-    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
-        int64_t lastEndTimeUs = mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
-        int64_t firstStartTimeUs = mTextVector.keyAt(0);
-
-        if (seekTimeUs < 0 || seekTimeUs > lastEndTimeUs) {
-            return ERROR_OUT_OF_RANGE;
-        } else if (seekTimeUs < firstStartTimeUs) {
-            mIndex = 0;
-        } else {
-            // binary search
-            ssize_t low = 0;
-            ssize_t high = mTextVector.size() - 1;
-            ssize_t mid = 0;
-            int64_t currTimeUs;
-
-            while (low <= high) {
-                mid = low + (high - low)/2;
-                currTimeUs = mTextVector.keyAt(mid);
-                const int diff = currTimeUs - seekTimeUs;
-
-                if (diff == 0) {
-                    break;
-                } else if (diff < 0) {
-                    low = mid + 1;
-                } else {
-                    if ((high == mid + 1)
-                            && (seekTimeUs < mTextVector.keyAt(high))) {
-                        break;
-                    }
-                    high = mid - 1;
-                }
-            }
-
-            mIndex = mid;
-        }
-    }
-
-    TextInfo info = mTextVector.valueAt(mIndex);
-    *startTimeUs = mTextVector.keyAt(mIndex);
-    *endTimeUs = info.endTimeUs;
-    mIndex ++;
-
-    char *str = new char[info.textLen];
-    if (mDataSource->readAt(info.offset, str, info.textLen) < info.textLen) {
-        delete[] str;
-        return ERROR_IO;
-    }
-
-    text->append(str, info.textLen);
-    delete[] str;
-    return OK;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextParser.h b/media/libstagefright/timedtext/TimedTextParser.h
deleted file mode 100644
index 44774c2..0000000
--- a/media/libstagefright/timedtext/TimedTextParser.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIMED_TEXT_PARSER_H_
-
-#define TIMED_TEXT_PARSER_H_
-
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/MediaSource.h>
-
-namespace android {
-
-class DataSource;
-
-class TimedTextParser : public RefBase {
-public:
-    TimedTextParser();
-    virtual ~TimedTextParser();
-
-    enum FileType {
-        OUT_OF_BAND_FILE_SRT = 1,
-    };
-
-    status_t getText(AString *text, int64_t *startTimeUs, int64_t *endTimeUs,
-                     const MediaSource::ReadOptions *options = NULL);
-    status_t init(const sp<DataSource> &dataSource, FileType fileType);
-    void reset();
-
-private:
-    Mutex mLock;
-
-    sp<DataSource> mDataSource;
-    off64_t mOffset;
-
-    struct TextInfo {
-        int64_t endTimeUs;
-        // the offset of the text in the original file
-        off64_t offset;
-        int textLen;
-    };
-
-    int mIndex;
-    FileType mFileType;
-
-    // the key indicated the start time of the text
-    KeyedVector<int64_t, TextInfo> mTextVector;
-
-    status_t getNextInSrtFileFormat(
-            off64_t *offset, int64_t *startTimeUs, TextInfo *info);
-    status_t readNextLine(off64_t *offset, AString *data);
-
-    status_t scanFile();
-
-    DISALLOW_EVIL_CONSTRUCTORS(TimedTextParser);
-};
-
-}  // namespace android
-
-#endif  // TIMED_TEXT_PARSER_H_
-
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 3014b0b..bf7cbf6 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -1,5 +1,5 @@
  /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -18,399 +18,164 @@
 #define LOG_TAG "TimedTextPlayer"
 #include <utils/Log.h>
 
-#include <binder/IPCThreadState.h>
-
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/MediaPlayerInterface.h>
 
-#include "include/AwesomePlayer.h"
 #include "TimedTextPlayer.h"
-#include "TimedTextParser.h"
-#include "TextDescriptions.h"
+
+#include "TimedTextDriver.h"
+#include "TimedTextSource.h"
 
 namespace android {
 
-struct TimedTextEvent : public TimedEventQueue::Event {
-    TimedTextEvent(
-            TimedTextPlayer *player,
-            void (TimedTextPlayer::*method)())
-        : mPlayer(player),
-          mMethod(method) {
-    }
+static const int64_t kAdjustmentProcessingTimeUs = 100000ll;
 
-protected:
-    virtual ~TimedTextEvent() {}
-
-    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
-        (mPlayer->*mMethod)();
-    }
-
-private:
-    TimedTextPlayer *mPlayer;
-    void (TimedTextPlayer::*mMethod)();
-
-    TimedTextEvent(const TimedTextEvent &);
-    TimedTextEvent &operator=(const TimedTextEvent &);
-};
-
-TimedTextPlayer::TimedTextPlayer(
-        AwesomePlayer *observer,
-        const wp<MediaPlayerBase> &listener,
-        TimedEventQueue *queue)
-    : mSource(NULL),
-      mOutOfBandSource(NULL),
-      mSeekTimeUs(0),
-      mStarted(false),
-      mTextEventPending(false),
-      mQueue(queue),
-      mListener(listener),
-      mObserver(observer),
-      mTextBuffer(NULL),
-      mTextParser(NULL),
-      mTextType(kNoText) {
-    mTextEvent = new TimedTextEvent(this, &TimedTextPlayer::onTextEvent);
+TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener)
+    : mListener(listener),
+      mSource(NULL),
+      mSendSubtitleGeneration(0) {
 }
 
 TimedTextPlayer::~TimedTextPlayer() {
-    if (mStarted) {
-        reset();
+    if (mSource != NULL) {
+        mSource->stop();
+        mSource.clear();
+        mSource = NULL;
     }
-
-    mTextTrackVector.clear();
-    mTextOutOfBandVector.clear();
 }
 
-status_t TimedTextPlayer::start(uint8_t index) {
-    CHECK(!mStarted);
-
-    if (index >=
-            mTextTrackVector.size() + mTextOutOfBandVector.size()) {
-        ALOGE("Incorrect text track index: %d", index);
-        return BAD_VALUE;
-    }
-
-    status_t err;
-    if (index < mTextTrackVector.size()) { // start an in-band text
-        mSource = mTextTrackVector.itemAt(index);
-
-        err = mSource->start();
-
-        if (err != OK) {
-            return err;
-        }
-        mTextType = kInBandText;
-    } else { // start an out-of-band text
-        OutOfBandText text =
-            mTextOutOfBandVector.itemAt(index - mTextTrackVector.size());
-
-        mOutOfBandSource = text.source;
-        TimedTextParser::FileType fileType = text.type;
-
-        if (mTextParser == NULL) {
-            mTextParser = new TimedTextParser();
-        }
-
-        if ((err = mTextParser->init(mOutOfBandSource, fileType)) != OK) {
-            return err;
-        }
-        mTextType = kOutOfBandText;
-    }
-
-    // send sample description format
-    if ((err = extractAndSendGlobalDescriptions()) != OK) {
-        return err;
-    }
-
-    int64_t positionUs;
-    mObserver->getPosition(&positionUs);
-    seekTo(positionUs);
-
-    postTextEvent();
-
-    mStarted = true;
-
-    return OK;
+void TimedTextPlayer::start() {
+    sp<AMessage> msg = new AMessage(kWhatSeek, id());
+    msg->setInt64("seekTimeUs", -1);
+    msg->post();
 }
 
 void TimedTextPlayer::pause() {
-    CHECK(mStarted);
-
-    cancelTextEvent();
+    (new AMessage(kWhatPause, id()))->post();
 }
 
 void TimedTextPlayer::resume() {
-    CHECK(mStarted);
-
-    postTextEvent();
+    start();
 }
 
-void TimedTextPlayer::reset() {
-    CHECK(mStarted);
+void TimedTextPlayer::seekToAsync(int64_t timeUs) {
+    sp<AMessage> msg = new AMessage(kWhatSeek, id());
+    msg->setInt64("seekTimeUs", timeUs);
+    msg->post();
+}
 
-    // send an empty text to clear the screen
-    notifyListener(MEDIA_TIMED_TEXT);
+void TimedTextPlayer::setDataSource(sp<TimedTextSource> source) {
+    sp<AMessage> msg = new AMessage(kWhatSetSource, id());
+    msg->setObject("source", source);
+    msg->post();
+}
 
-    cancelTextEvent();
-
-    mSeeking = false;
-    mStarted = false;
-
-    if (mTextType == kInBandText) {
-        if (mTextBuffer != NULL) {
-            mTextBuffer->release();
-            mTextBuffer = NULL;
+void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatPause: {
+            mSendSubtitleGeneration++;
+            break;
         }
-
-        if (mSource != NULL) {
-            mSource->stop();
-            mSource.clear();
-            mSource = NULL;
+        case kWhatSeek: {
+            int64_t seekTimeUs = 0;
+            msg->findInt64("seekTimeUs", &seekTimeUs);
+            if (seekTimeUs < 0) {
+                sp<MediaPlayerBase> listener = mListener.promote();
+                if (listener != NULL) {
+                    int32_t positionMs = 0;
+                    listener->getCurrentPosition(&positionMs);
+                    seekTimeUs = positionMs * 1000ll;
+                }
+            }
+            doSeekAndRead(seekTimeUs);
+            break;
         }
-    } else {
-        if (mTextParser != NULL) {
-            mTextParser.clear();
-            mTextParser = NULL;
+        case kWhatSendSubtitle: {
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+            if (generation != mSendSubtitleGeneration) {
+              // Drop obsolete msg.
+              break;
+            }
+            sp<RefBase> obj;
+            msg->findObject("subtitle", &obj);
+            if (obj != NULL) {
+                sp<ParcelEvent> parcelEvent;
+                parcelEvent = static_cast<ParcelEvent*>(obj.get());
+                notifyListener(MEDIA_TIMED_TEXT, &(parcelEvent->parcel));
+            } else {
+                notifyListener(MEDIA_TIMED_TEXT);
+            }
+            doRead();
+            break;
         }
-        if (mOutOfBandSource != NULL) {
-            mOutOfBandSource.clear();
-            mOutOfBandSource = NULL;
+        case kWhatSetSource: {
+            sp<RefBase> obj;
+            msg->findObject("source", &obj);
+            if (obj == NULL) break;
+            if (mSource != NULL) {
+                mSource->stop();
+            }
+            mSource = static_cast<TimedTextSource*>(obj.get());
+            mSource->start();
+            Parcel parcel;
+            if (mSource->extractGlobalDescriptions(&parcel) == OK &&
+                parcel.dataSize() > 0) {
+                notifyListener(MEDIA_TIMED_TEXT, &parcel);
+            } else {
+                notifyListener(MEDIA_TIMED_TEXT);
+            }
+            break;
         }
     }
 }
 
-status_t TimedTextPlayer::seekTo(int64_t time_us) {
-    Mutex::Autolock autoLock(mLock);
-
-    mSeeking = true;
-    mSeekTimeUs = time_us;
-
-    postTextEvent();
-
-    return OK;
-}
-
-status_t TimedTextPlayer::setTimedTextTrackIndex(int32_t index) {
-    if (index >=
-            (int)(mTextTrackVector.size() + mTextOutOfBandVector.size())) {
-        return BAD_VALUE;
-    }
-
-    if (mStarted) {
-        reset();
-    }
-
-    if (index >= 0) {
-        return start(index);
-    }
-    return OK;
-}
-
-void TimedTextPlayer::onTextEvent() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (!mTextEventPending) {
-        return;
-    }
-    mTextEventPending = false;
-
-    if (mData.dataSize() > 0) {
-        notifyListener(MEDIA_TIMED_TEXT, &mData);
-        mData.freeData();
-    }
-
+void TimedTextPlayer::doSeekAndRead(int64_t seekTimeUs) {
     MediaSource::ReadOptions options;
-    if (mSeeking) {
-        options.setSeekTo(mSeekTimeUs,
-                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
-        mSeeking = false;
-
-        notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen
-    }
-
-    int64_t positionUs, timeUs;
-    mObserver->getPosition(&positionUs);
-
-    if (mTextType == kInBandText) {
-        if (mSource->read(&mTextBuffer, &options) != OK) {
-            return;
-        }
-
-        mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs);
-    } else {
-        int64_t endTimeUs;
-        if (mTextParser->getText(
-                    &mText, &timeUs, &endTimeUs, &options) != OK) {
-            return;
-        }
-    }
-
-    if (timeUs > 0) {
-        extractAndAppendLocalDescriptions(timeUs);
-    }
-
-    if (mTextType == kInBandText) {
-        if (mTextBuffer != NULL) {
-            mTextBuffer->release();
-            mTextBuffer = NULL;
-        }
-    } else {
-        mText.clear();
-    }
-
-    //send the text now
-    if (timeUs <= positionUs + 100000ll) {
-        postTextEvent();
-    } else {
-        postTextEvent(timeUs - positionUs - 100000ll);
-    }
+    options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    doRead(&options);
 }
 
-void TimedTextPlayer::postTextEvent(int64_t delayUs) {
-    if (mTextEventPending) {
-        return;
-    }
-
-    mTextEventPending = true;
-    mQueue->postEventWithDelay(mTextEvent, delayUs < 0 ? 10000 : delayUs);
+void TimedTextPlayer::doRead(MediaSource::ReadOptions* options) {
+    int64_t timeUs = 0;
+    sp<ParcelEvent> parcelEvent = new ParcelEvent();
+    mSource->read(&timeUs, &(parcelEvent->parcel), options);
+    postTextEvent(parcelEvent, timeUs);
 }
 
-void TimedTextPlayer::cancelTextEvent() {
-    mQueue->cancelEvent(mTextEvent->eventID());
-    mTextEventPending = false;
-}
+void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) {
+    sp<MediaPlayerBase> listener = mListener.promote();
+    if (listener != NULL) {
+        int64_t positionUs, delayUs;
+        int32_t positionMs = 0;
+        listener->getCurrentPosition(&positionMs);
+        positionUs = positionMs * 1000;
 
-void TimedTextPlayer::addTextSource(sp<MediaSource> source) {
-    Mutex::Autolock autoLock(mLock);
-    mTextTrackVector.add(source);
-}
-
-status_t TimedTextPlayer::setParameter(int key, const Parcel &request) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (key == KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE) {
-        const String16 uri16 = request.readString16();
-        String8 uri = String8(uri16);
-        KeyedVector<String8, String8> headers;
-
-        // To support local subtitle file only for now
-        if (strncasecmp("file://", uri.string(), 7)) {
-            return INVALID_OPERATION;
-        }
-        sp<DataSource> dataSource =
-            DataSource::CreateFromURI(uri, &headers);
-        status_t err = dataSource->initCheck();
-
-        if (err != OK) {
-            return err;
-        }
-
-        OutOfBandText text;
-        text.source = dataSource;
-        if (uri.getPathExtension() == String8(".srt")) {
-            text.type = TimedTextParser::OUT_OF_BAND_FILE_SRT;
+        if (timeUs <= positionUs + kAdjustmentProcessingTimeUs) {
+            delayUs = 0;
         } else {
-            return ERROR_UNSUPPORTED;
+            delayUs = timeUs - positionUs - kAdjustmentProcessingTimeUs;
         }
-
-        mTextOutOfBandVector.add(text);
-
-        return OK;
+        sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id());
+        msg->setInt32("generation", mSendSubtitleGeneration);
+        if (parcel != NULL) {
+            msg->setObject("subtitle", parcel);
+        }
+        msg->post(delayUs);
     }
-    return INVALID_OPERATION;
 }
 
 void TimedTextPlayer::notifyListener(int msg, const Parcel *parcel) {
-    if (mListener != NULL) {
-        sp<MediaPlayerBase> listener = mListener.promote();
-
-        if (listener != NULL) {
-            if (parcel && (parcel->dataSize() > 0)) {
-                listener->sendEvent(msg, 0, 0, parcel);
-            } else { // send an empty timed text to clear the screen
-                listener->sendEvent(msg);
-            }
+    sp<MediaPlayerBase> listener = mListener.promote();
+    if (listener != NULL) {
+        if (parcel != NULL && (parcel->dataSize() > 0)) {
+            listener->sendEvent(msg, 0, 0, parcel);
+        } else {  // send an empty timed text to clear the screen
+            listener->sendEvent(msg);
         }
     }
 }
 
-// Each text sample consists of a string of text, optionally with sample
-// modifier description. The modifier description could specify a new
-// text style for the string of text. These descriptions are present only
-// if they are needed. This method is used to extract the modifier
-// description and append it at the end of the text.
-status_t TimedTextPlayer::extractAndAppendLocalDescriptions(int64_t timeUs) {
-    const void *data;
-    size_t size = 0;
-    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
-
-    if (mTextType == kInBandText) {
-        const char *mime;
-        CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-
-        if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
-            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
-            data = mTextBuffer->data();
-            size = mTextBuffer->size();
-        } else {
-            // support 3GPP only for now
-            return ERROR_UNSUPPORTED;
-        }
-    } else {
-        data = mText.c_str();
-        size = mText.size();
-        flag |= TextDescriptions::OUT_OF_BAND_TEXT_SRT;
-    }
-
-    if ((size > 0) && (flag != TextDescriptions::LOCAL_DESCRIPTIONS)) {
-        mData.freeData();
-        return TextDescriptions::getParcelOfDescriptions(
-                (const uint8_t *)data, size, flag, timeUs / 1000, &mData);
-    }
-
-    return OK;
-}
-
-// To extract and send the global text descriptions for all the text samples
-// in the text track or text file.
-status_t TimedTextPlayer::extractAndSendGlobalDescriptions() {
-    const void *data;
-    size_t size = 0;
-    int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS;
-
-    if (mTextType == kInBandText) {
-        const char *mime;
-        CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-
-        // support 3GPP only for now
-        if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
-            uint32_t type;
-            // get the 'tx3g' box content. This box contains the text descriptions
-            // used to render the text track
-            if (!mSource->getFormat()->findData(
-                        kKeyTextFormatData, &type, &data, &size)) {
-                return ERROR_MALFORMED;
-            }
-
-            flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
-        }
-    }
-
-    if ((size > 0) && (flag != TextDescriptions::GLOBAL_DESCRIPTIONS)) {
-        Parcel parcel;
-        if (TextDescriptions::getParcelOfDescriptions(
-                (const uint8_t *)data, size, flag, 0, &parcel) == OK) {
-            if (parcel.dataSize() > 0) {
-                notifyListener(MEDIA_TIMED_TEXT, &parcel);
-            }
-        }
-    }
-
-    return OK;
-}
-}
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
index a744db5..837beeb 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -15,99 +15,61 @@
  */
 
 #ifndef TIMEDTEXT_PLAYER_H_
-
 #define TIMEDTEXT_PLAYER_H_
 
-#include <media/MediaPlayerInterface.h>
+#include <binder/Parcel.h>
 #include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/RefBase.h>
 
-#include "include/TimedEventQueue.h"
-#include "TimedTextParser.h"
+#include "TimedTextSource.h"
 
 namespace android {
 
-class MediaSource;
-class AwesomePlayer;
-class MediaBuffer;
+class AMessage;
+class MediaPlayerBase;
+class TimedTextDriver;
+class TimedTextSource;
 
-class TimedTextPlayer {
+class TimedTextPlayer : public AHandler {
 public:
-    TimedTextPlayer(AwesomePlayer *observer,
-                    const wp<MediaPlayerBase> &listener,
-                    TimedEventQueue *queue);
+    TimedTextPlayer(const wp<MediaPlayerBase> &listener);
 
     virtual ~TimedTextPlayer();
 
-    // index: the index of the text track which will
-    // be turned on
-    status_t start(uint8_t index);
-
+    void start();
     void pause();
-
     void resume();
+    void seekToAsync(int64_t timeUs);
+    void setDataSource(sp<TimedTextSource> source);
 
-    status_t seekTo(int64_t time_us);
-
-    void addTextSource(sp<MediaSource> source);
-
-    status_t setTimedTextTrackIndex(int32_t index);
-    status_t setParameter(int key, const Parcel &request);
+protected:
+    virtual void onMessageReceived(const sp<AMessage> &msg);
 
 private:
-    enum TextType {
-        kNoText        = 0,
-        kInBandText    = 1,
-        kOutOfBandText = 2,
+    enum {
+        kWhatPause = 'paus',
+        kWhatSeek = 'seek',
+        kWhatSendSubtitle = 'send',
+        kWhatSetSource = 'ssrc',
     };
 
-    Mutex mLock;
-
-    sp<MediaSource> mSource;
-    sp<DataSource> mOutOfBandSource;
-
-    bool mSeeking;
-    int64_t mSeekTimeUs;
-
-    bool mStarted;
-
-    sp<TimedEventQueue::Event> mTextEvent;
-    bool mTextEventPending;
-
-    TimedEventQueue *mQueue;
+    // To add Parcel into an AMessage as an object, it should be 'RefBase'.
+    struct ParcelEvent : public RefBase {
+        Parcel parcel;
+    };
 
     wp<MediaPlayerBase> mListener;
-    AwesomePlayer *mObserver;
+    sp<TimedTextSource> mSource;
+    int32_t mSendSubtitleGeneration;
 
-    MediaBuffer *mTextBuffer;
-    Parcel mData;
-
-    // for in-band timed text
-    Vector<sp<MediaSource> > mTextTrackVector;
-
-    // for out-of-band timed text
-    struct OutOfBandText {
-        TimedTextParser::FileType type;
-        sp<DataSource> source;
-    };
-    Vector<OutOfBandText > mTextOutOfBandVector;
-
-    sp<TimedTextParser> mTextParser;
-    AString mText;
-
-    TextType mTextType;
-
-    void reset();
-
+    void doSeekAndRead(int64_t seekTimeUs);
+    void doRead(MediaSource::ReadOptions* options = NULL);
     void onTextEvent();
-    void postTextEvent(int64_t delayUs = -1);
-    void cancelTextEvent();
-
+    void postTextEvent(const sp<ParcelEvent>& parcel = NULL, int64_t timeUs = -1);
     void notifyListener(int msg, const Parcel *parcel = NULL);
 
-    status_t extractAndAppendLocalDescriptions(int64_t timeUs);
-    status_t extractAndSendGlobalDescriptions();
-
     DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
 };
 
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.cpp b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
new file mode 100644
index 0000000..3752d34
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
@@ -0,0 +1,275 @@
+ /*
+ * Copyright (C) 2012 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 "TimedTextSRTSource"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+
+#include "TimedTextSRTSource.h"
+#include "TextDescriptions.h"
+
+namespace android {
+
+TimedTextSRTSource::TimedTextSRTSource(const sp<DataSource>& dataSource)
+        : mSource(dataSource),
+          mIndex(0) {
+}
+
+TimedTextSRTSource::~TimedTextSRTSource() {
+}
+
+status_t TimedTextSRTSource::start() {
+    status_t err = scanFile();
+    if (err != OK) {
+        reset();
+    }
+    return err;
+}
+
+void TimedTextSRTSource::reset() {
+    mTextVector.clear();
+    mIndex = 0;
+}
+
+status_t TimedTextSRTSource::stop() {
+    reset();
+    return OK;
+}
+
+status_t TimedTextSRTSource::read(
+        int64_t *timeUs,
+        Parcel *parcel,
+        const MediaSource::ReadOptions *options) {
+    int64_t endTimeUs;
+    AString text;
+    status_t err = getText(options, &text, timeUs, &endTimeUs);
+    if (err != OK) {
+        return err;
+    }
+
+    if (*timeUs > 0) {
+        extractAndAppendLocalDescriptions(*timeUs, text, parcel);
+    }
+    return OK;
+}
+
+status_t TimedTextSRTSource::scanFile() {
+    off64_t offset = 0;
+    int64_t startTimeUs;
+    bool endOfFile = false;
+
+    while (!endOfFile) {
+        TextInfo info;
+        status_t err = getNextSubtitleInfo(&offset, &startTimeUs, &info);
+        switch (err) {
+            case OK:
+                mTextVector.add(startTimeUs, info);
+                break;
+            case ERROR_END_OF_STREAM:
+                endOfFile = true;
+                break;
+            default:
+                return err;
+        }
+    }
+    if (mTextVector.isEmpty()) {
+        return ERROR_MALFORMED;
+    }
+    return OK;
+}
+
+/* SRT format:
+ *   Subtitle number
+ *   Start time --> End time
+ *   Text of subtitle (one or more lines)
+ *   Blank lines
+ *
+ * .srt file example:
+ * 1
+ * 00:00:20,000 --> 00:00:24,400
+ * Altocumulus clouds occr between six thousand
+ *
+ * 2
+ * 00:00:24,600 --> 00:00:27,800
+ * and twenty thousand feet above ground level.
+ */
+status_t TimedTextSRTSource::getNextSubtitleInfo(
+          off64_t *offset, int64_t *startTimeUs, TextInfo *info) {
+    AString data;
+    status_t err;
+
+    // To skip blank lines.
+    do {
+        if ((err = readNextLine(offset, &data)) != OK) {
+            return err;
+        }
+        data.trim();
+    } while (data.empty());
+
+    // Just ignore the first non-blank line which is subtitle sequence number.
+    if ((err = readNextLine(offset, &data)) != OK) {
+        return err;
+    }
+    int hour1, hour2, min1, min2, sec1, sec2, msec1, msec2;
+    // the start time format is: hours:minutes:seconds,milliseconds
+    // 00:00:24,600 --> 00:00:27,800
+    if (sscanf(data.c_str(), "%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d",
+               &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) {
+        return ERROR_MALFORMED;
+    }
+
+    *startTimeUs = ((hour1 * 3600 + min1 * 60 + sec1) * 1000 + msec1) * 1000ll;
+    info->endTimeUs = ((hour2 * 3600 + min2 * 60 + sec2) * 1000 + msec2) * 1000ll;
+    if (info->endTimeUs <= *startTimeUs) {
+        return ERROR_MALFORMED;
+    }
+
+    info->offset = *offset;
+    bool needMoreData = true;
+    while (needMoreData) {
+        if ((err = readNextLine(offset, &data)) != OK) {
+            if (err == ERROR_END_OF_STREAM) {
+                needMoreData = false;
+            } else {
+                return err;
+            }
+        }
+
+        if (needMoreData) {
+            data.trim();
+            if (data.empty()) {
+                // it's an empty line used to separate two subtitles
+                needMoreData = false;
+            }
+        }
+    }
+    info->textLen = *offset - info->offset;
+    return OK;
+}
+
+status_t TimedTextSRTSource::readNextLine(off64_t *offset, AString *data) {
+    data->clear();
+    while (true) {
+        ssize_t readSize;
+        char character;
+        if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
+            if (readSize == 0) {
+                return ERROR_END_OF_STREAM;
+            }
+            return ERROR_IO;
+        }
+
+        (*offset)++;
+
+        // a line could end with CR, LF or CR + LF
+        if (character == 10) {
+            break;
+        } else if (character == 13) {
+            if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
+                if (readSize == 0) {  // end of the stream
+                    return OK;
+                }
+                return ERROR_IO;
+            }
+
+            (*offset)++;
+            if (character != 10) {
+                (*offset)--;
+            }
+            break;
+        }
+        data->append(character);
+    }
+    return OK;
+}
+
+status_t TimedTextSRTSource::getText(
+        const MediaSource::ReadOptions *options,
+        AString *text, int64_t *startTimeUs, int64_t *endTimeUs) {
+    text->clear();
+    int64_t seekTimeUs;
+    MediaSource::ReadOptions::SeekMode mode;
+    if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
+        int64_t lastEndTimeUs =
+                mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
+        int64_t firstStartTimeUs = mTextVector.keyAt(0);
+        if (seekTimeUs < 0 || seekTimeUs > lastEndTimeUs) {
+            return ERROR_OUT_OF_RANGE;
+        } else if (seekTimeUs < firstStartTimeUs) {
+            mIndex = 0;
+        } else {
+            // binary search
+            ssize_t low = 0;
+            ssize_t high = mTextVector.size() - 1;
+            ssize_t mid = 0;
+            int64_t currTimeUs;
+
+            while (low <= high) {
+                mid = low + (high - low)/2;
+                currTimeUs = mTextVector.keyAt(mid);
+                const int diff = currTimeUs - seekTimeUs;
+
+                if (diff == 0) {
+                    break;
+                } else if (diff < 0) {
+                    low = mid + 1;
+                } else {
+                    if ((high == mid + 1)
+                        && (seekTimeUs < mTextVector.keyAt(high))) {
+                        break;
+                    }
+                    high = mid - 1;
+                }
+            }
+            mIndex = mid;
+        }
+    }
+    const TextInfo &info = mTextVector.valueAt(mIndex);
+    *startTimeUs = mTextVector.keyAt(mIndex);
+    *endTimeUs = info.endTimeUs;
+    mIndex++;
+
+    char *str = new char[info.textLen];
+    if (mSource->readAt(info.offset, str, info.textLen) < info.textLen) {
+        delete[] str;
+        return ERROR_IO;
+    }
+    text->append(str, info.textLen);
+    delete[] str;
+    return OK;
+}
+
+status_t TimedTextSRTSource::extractAndAppendLocalDescriptions(
+        int64_t timeUs, const AString &text, Parcel *parcel) {
+    const void *data = text.c_str();
+    size_t size = text.size();
+    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS |
+                   TextDescriptions::OUT_OF_BAND_TEXT_SRT;
+
+    if (size > 0) {
+        return TextDescriptions::getParcelOfDescriptions(
+                (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
+    }
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h
new file mode 100644
index 0000000..a0734d9
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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 TIMED_TEXT_SRT_SOURCE_H_
+#define TIMED_TEXT_SRT_SOURCE_H_
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/Compat.h>  // off64_t
+
+#include "TimedTextSource.h"
+
+namespace android {
+
+class AString;
+class DataSource;
+class MediaBuffer;
+class Parcel;
+
+class TimedTextSRTSource : public TimedTextSource {
+ public:
+  TimedTextSRTSource(const sp<DataSource>& dataSource);
+  virtual status_t start();
+  virtual status_t stop();
+  virtual status_t read(
+          int64_t *timeUs,
+          Parcel *parcel,
+          const MediaSource::ReadOptions *options = NULL);
+
+ protected:
+  virtual ~TimedTextSRTSource();
+
+ private:
+  sp<DataSource> mSource;
+
+  struct TextInfo {
+      int64_t endTimeUs;
+      // The offset of the text in the original file.
+      off64_t offset;
+      int textLen;
+  };
+
+  int mIndex;
+  KeyedVector<int64_t, TextInfo> mTextVector;
+
+  void reset();
+  status_t scanFile();
+  status_t getNextSubtitleInfo(
+          off64_t *offset, int64_t *startTimeUs, TextInfo *info);
+  status_t readNextLine(off64_t *offset, AString *data);
+  status_t getText(
+          const MediaSource::ReadOptions *options,
+          AString *text, int64_t *startTimeUs, int64_t *endTimeUs);
+  status_t extractAndAppendLocalDescriptions(
+          int64_t timeUs, const AString &text, Parcel *parcel);
+
+  DISALLOW_EVIL_CONSTRUCTORS(TimedTextSRTSource);
+};
+
+}  // namespace android
+
+#endif  // TIMED_TEXT_SRT_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextSource.cpp b/media/libstagefright/timedtext/TimedTextSource.cpp
new file mode 100644
index 0000000..9efe67c
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSource.cpp
@@ -0,0 +1,53 @@
+ /*
+ * Copyright (C) 2012 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 "TimedTextSource"
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaSource.h>
+
+#include "TimedTextSource.h"
+
+#include "TimedTextInBandSource.h"
+#include "TimedTextSRTSource.h"
+
+namespace android {
+
+// static
+sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
+        const sp<MediaSource>& mediaSource) {
+    return new TimedTextInBandSource(mediaSource);
+}
+
+// static
+sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
+        const sp<DataSource>& dataSource, FileType filetype) {
+    switch(filetype) {
+        case OUT_OF_BAND_FILE_SRT:
+            return new TimedTextSRTSource(dataSource);
+        case OUT_OF_BAND_FILE_SMI:
+            // TODO: Implement for SMI.
+            ALOGE("Supporting SMI is not implemented yet");
+            break;
+        default:
+            ALOGE("Undefined subtitle format. : %d", filetype);
+    }
+    return NULL;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h
new file mode 100644
index 0000000..06bae71
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSource.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 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 TIMED_TEXT_SOURCE_H_
+#define TIMED_TEXT_SOURCE_H_
+
+#include <media/stagefright/foundation/ABase.h>  // for DISALLOW_XXX macro.
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>  // for MediaSource::ReadOptions
+#include <utils/RefBase.h>
+
+namespace android {
+
+class DataSource;
+class Parcel;
+
+class TimedTextSource : public RefBase {
+ public:
+  enum FileType {
+      OUT_OF_BAND_FILE_SRT = 1,
+      OUT_OF_BAND_FILE_SMI = 2,
+  };
+  static sp<TimedTextSource> CreateTimedTextSource(
+      const sp<MediaSource>& source);
+  static sp<TimedTextSource> CreateTimedTextSource(
+      const sp<DataSource>& source, FileType filetype);
+  TimedTextSource() {}
+  virtual status_t start() = 0;
+  virtual status_t stop() = 0;
+  // Returns subtitle parcel and its start time.
+  virtual status_t read(
+          int64_t *timeUs,
+          Parcel *parcel,
+          const MediaSource::ReadOptions *options = NULL) = 0;
+  virtual status_t extractGlobalDescriptions(Parcel *parcel) {
+      return INVALID_OPERATION;
+  }
+
+ protected:
+  virtual ~TimedTextSource() { }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(TimedTextSource);
+};
+
+}  // namespace android
+
+#endif  // TIMED_TEXT_SOURCE_H_
diff --git a/media/libstagefright/yuv/YUVCanvas.cpp b/media/libstagefright/yuv/YUVCanvas.cpp
index 38aa779..4c9fee8 100644
--- a/media/libstagefright/yuv/YUVCanvas.cpp
+++ b/media/libstagefright/yuv/YUVCanvas.cpp
@@ -17,7 +17,7 @@
 #define LOG_NDEBUG 0
 #define LOG_TAG "YUVCanvas"
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/YUVCanvas.h>
 #include <media/stagefright/YUVImage.h>
 #include <ui/Rect.h>
diff --git a/media/libstagefright/yuv/YUVImage.cpp b/media/libstagefright/yuv/YUVImage.cpp
index 0d67c96..7b9000b 100644
--- a/media/libstagefright/yuv/YUVImage.cpp
+++ b/media/libstagefright/yuv/YUVImage.cpp
@@ -17,9 +17,9 @@
 #define LOG_NDEBUG 0
 #define LOG_TAG "YUVImage"
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/YUVImage.h>
 #include <ui/Rect.h>
-#include <media/stagefright/MediaDebug.h>
 
 namespace android {
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
index c9087d1..7967ce7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
@@ -19,8 +19,13 @@
 import com.android.mediaframeworktest.MediaFrameworkTest;
 import android.content.Context;
 import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.AudioManager.OnAudioFocusChangeListener;
+import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
 
 /**
  * Junit / Instrumentation test case for the media AudioManager api
@@ -28,8 +33,13 @@
 
 public class MediaAudioManagerTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
 
-    private String TAG = "MediaAudioManagerTest";
+    private final static String TAG = "MediaAudioManagerTest";
+    // the AudioManager used throughout the test
     private AudioManager mAudioManager;
+    // keep track of looper for AudioManager so we can terminate it
+    private Looper mAudioManagerLooper;
+    private final Object mLooperLock = new Object();
+    private final static int WAIT_FOR_LOOPER_TO_INITIALIZE_MS = 60000;  // 60s
     private int[] ringtoneMode = {AudioManager.RINGER_MODE_NORMAL,
              AudioManager.RINGER_MODE_SILENT, AudioManager.RINGER_MODE_VIBRATE};
 
@@ -37,17 +47,48 @@
         super("com.android.mediaframeworktest", MediaFrameworkTest.class);
     }
 
+    private void initializeAudioManagerWithLooper() {
+        new Thread() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                mAudioManagerLooper = Looper.myLooper();
+                mAudioManager = (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE);
+                synchronized (mLooperLock) {
+                    mLooperLock.notify();
+                }
+                Looper.loop();
+            }
+        }.start();
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+        synchronized(mLooperLock) {
+            initializeAudioManagerWithLooper();
+            try {
+                mLooperLock.wait(WAIT_FOR_LOOPER_TO_INITIALIZE_MS);
+            } catch (Exception e) {
+                assertTrue("initializeAudioManagerWithLooper() failed to complete in time", false);
+            }
+        }
      }
 
      @Override
      protected void tearDown() throws Exception {
          super.tearDown();
+         synchronized(mLooperLock) {
+             if (mAudioManagerLooper != null) {
+                 mAudioManagerLooper.quit();
+             }
+         }
      }
 
+     //-----------------------------------------------------------------
+     //      Ringer Mode
+     //----------------------------------
+
      public boolean validateSetRingTone(int i) {
          int getRingtone = mAudioManager.getRingerMode();
          if (i != getRingtone)
@@ -67,4 +108,136 @@
              assertTrue("SetRingtoneMode : " + ringtoneMode[i], result);
          }
      }
+
+    //-----------------------------------------------------------------
+    //      AudioFocus
+    //----------------------------------
+
+    private static AudioFocusListener mAudioFocusListener;
+    private final static int INVALID_FOCUS = -80; // initialized to magic invalid focus change type
+    private final static int WAIT_FOR_AUDIOFOCUS_LOSS_MS = 10;
+
+    private static class AudioFocusListener implements OnAudioFocusChangeListener {
+        public int mLastFocusChange = INVALID_FOCUS;
+        public int mFocusChangeCounter = 0;
+        public AudioFocusListener() {
+        }
+        public void onAudioFocusChange(int focusChange) {
+            mLastFocusChange = focusChange;
+            mFocusChangeCounter++;
+        }
+    }
+
+    /**
+     * Fails the test if expectedFocusLossMode != mAudioFocusListener.mLastFocusChange
+     */
+    private void verifyAudioFocusLoss(int focusGainMode, int expectedFocusLossMode)
+            throws Exception {
+        // request AudioFocus so we can test that mAudioFocusListener loses it when another
+        //     request comes in
+        int result = mAudioManager.requestAudioFocus(mAudioFocusListener,
+                AudioManager.STREAM_MUSIC,
+                AudioManager.AUDIOFOCUS_GAIN);
+        assertTrue("requestAudioFocus returned " + result,
+                result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+        // cause mAudioFocusListener to lose AudioFocus
+        result = mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
+                focusGainMode);
+        assertTrue("requestAudioFocus returned " + result,
+                result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+        // the audio focus request is async, so wait a bit to verify it had the expected effect
+        java.lang.Thread.sleep(WAIT_FOR_AUDIOFOCUS_LOSS_MS);
+        // test successful if the expected focus loss was recorded
+        assertEquals("listener lost focus",
+                mAudioFocusListener.mLastFocusChange, expectedFocusLossMode);
+    }
+
+    private void setupAudioFocusListener() {
+        mAudioFocusListener = new AudioFocusListener();
+        mAudioManager.registerAudioFocusListener(mAudioFocusListener);
+    }
+
+    private void cleanupAudioFocusListener() {
+        // clean up
+        mAudioManager.abandonAudioFocus(mAudioFocusListener);
+        mAudioManager.unregisterAudioFocusListener(mAudioFocusListener);
+    }
+
+    //----------------------------------
+
+    //Test case 1: test audio focus listener loses audio focus:
+    //   AUDIOFOCUS_GAIN causes AUDIOFOCUS_LOSS
+    @MediumTest
+    public void testAudioFocusLoss() throws Exception {
+        setupAudioFocusListener();
+
+        verifyAudioFocusLoss(AudioManager.AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_LOSS);
+
+        cleanupAudioFocusListener();
+    }
+
+    //Test case 2: test audio focus listener loses audio focus:
+    //   AUDIOFOCUS_GAIN_TRANSIENT causes AUDIOFOCUS_LOSS_TRANSIENT
+    @MediumTest
+    public void testAudioFocusLossTransient() throws Exception {
+        setupAudioFocusListener();
+
+        verifyAudioFocusLoss(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
+
+        cleanupAudioFocusListener();
+    }
+
+    //Test case 3: test audio focus listener loses audio focus:
+    //   AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK causes AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
+    @MediumTest
+    public void testAudioFocusLossTransientDuck() throws Exception {
+        setupAudioFocusListener();
+
+        verifyAudioFocusLoss(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+                AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
+
+        cleanupAudioFocusListener();
+    }
+
+    //Test case 4: test audio focus registering and use over 3000 iterations
+    @LargeTest
+    public void testAudioFocusStressListenerRequestAbandon() throws Exception {
+        final int ITERATIONS = 3000;
+        // here we only test the life cycle of a focus listener, and make sure we don't crash
+        // when doing it many times without waiting
+        for (int i = 0 ; i < ITERATIONS ; i++) {
+            setupAudioFocusListener();
+            int result = mAudioManager.requestAudioFocus(mAudioFocusListener,
+                    AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+            assertTrue("audio focus request was not granted",
+                    result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+            cleanupAudioFocusListener();
+        }
+        assertTrue("testAudioFocusListenerLifeCycle : tested" + ITERATIONS +" iterations", true);
+    }
+
+    //Test case 5: test audio focus use without listener
+    @LargeTest
+    public void testAudioFocusStressNoListenerRequestAbandon() throws Exception {
+        final int ITERATIONS = 1000;
+        // make sure we have a listener in the stack
+        setupAudioFocusListener();
+        mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
+                AudioManager.AUDIOFOCUS_GAIN);
+        // keep making the current owner lose and gain audio focus repeatedly
+        for (int i = 0 ; i < ITERATIONS ; i++) {
+            mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
+                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+            mAudioManager.abandonAudioFocus(null);
+            // the audio focus request is async, so wait a bit to verify it had the expected effect
+            java.lang.Thread.sleep(WAIT_FOR_AUDIOFOCUS_LOSS_MS);
+        }
+        // verify there were 2 audio focus changes per iteration (one loss + one gain)
+        assertTrue("testAudioFocusListenerLifeCycle : observed " +
+                mAudioFocusListener.mFocusChangeCounter + " AudioFocus changes",
+                mAudioFocusListener.mFocusChangeCounter == ITERATIONS * 2);
+        mAudioManager.abandonAudioFocus(mAudioFocusListener);
+        mAudioManager.unregisterAudioFocusListener(mAudioFocusListener);
+    }
  }
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 81c6167..025a131 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -26,6 +26,7 @@
     libcutils \
     libskia \
     libstagefright \
+    libstagefright_foundation \
     libbinder \
     libutils \
     libjpeg
diff --git a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp b/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
index dfdf676..a25e854 100644
--- a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
+++ b/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <SkBitmap.h>
 
 #include "SkOmxPixelRef.h"
@@ -32,7 +32,7 @@
 
 SkOmxPixelRef::~SkOmxPixelRef() {
     mBuffer->release();
-    CHECK_EQ(mDecoder->stop(), OK);
+    CHECK_EQ(mDecoder->stop(), (status_t)OK);
     SkSafeUnref(mCTable);
 }
 
diff --git a/media/tests/omxjpegdecoder/StreamSource.cpp b/media/tests/omxjpegdecoder/StreamSource.cpp
index 5f44203..f764121a 100644
--- a/media/tests/omxjpegdecoder/StreamSource.cpp
+++ b/media/tests/omxjpegdecoder/StreamSource.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 
 #include "StreamSource.h"
 
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index 42df66c..6424744 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -25,7 +25,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <media/IMediaPlayerService.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXClient.h>
@@ -89,7 +89,7 @@
 
 OmxJpegImageDecoder::OmxJpegImageDecoder() {
     status_t err = mClient.connect();
-    CHECK_EQ(err, OK);
+    CHECK_EQ(err, (status_t)OK);
 }
 
 OmxJpegImageDecoder::~OmxJpegImageDecoder() {
@@ -152,7 +152,7 @@
     int64_t duration = getNowUs() - startTime;
 
     if (err != OK) {
-        CHECK_EQ(buffer, NULL);
+        CHECK(buffer == NULL);
     }
     printf("Duration in decoder->read(): %.1f (msecs). \n",
                 duration / 1E3 );
diff --git a/native/include/android/configuration.h b/native/include/android/configuration.h
index 4d683fb..06cd3da 100644
--- a/native/include/android/configuration.h
+++ b/native/include/android/configuration.h
@@ -42,6 +42,8 @@
     ACONFIGURATION_DENSITY_MEDIUM = 160,
     ACONFIGURATION_DENSITY_TV = 213,
     ACONFIGURATION_DENSITY_HIGH = 240,
+    ACONFIGURATION_DENSITY_XHIGH = 320,
+    ACONFIGURATION_DENSITY_XXHIGH = 480,
     ACONFIGURATION_DENSITY_NONE = 0xffff,
 
     ACONFIGURATION_KEYBOARD_ANY  = 0x0000,
diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h
index 65ab5e4..54afaab 100644
--- a/opengl/include/GLES/glext.h
+++ b/opengl/include/GLES/glext.h
@@ -1,7 +1,7 @@
 #ifndef __glext_h_
 #define __glext_h_
 
-/* $Revision: 10965 $ on $Date:: 2010-04-09 02:11:29 -0700 #$ */
+/* $Revision: 16481 $ on $Date:: 2012-01-04 10:43:56 -0800 #$ */
 
 #ifdef __cplusplus
 extern "C" {
@@ -68,6 +68,14 @@
 typedef void* GLeglImageOES;
 #endif
 
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
+#define GL_TEXTURE_BINDING_EXTERNAL_OES                         0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES                     0x8D68
+#endif
+
 /* GL_OES_element_index_uint */
 #ifndef GL_OES_element_index_uint
 #define GL_UNSIGNED_INT                                         0x1405
@@ -211,14 +219,6 @@
 #define GL_VERTEX_ARRAY_BINDING_OES                             0x85B5
 #endif
 
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
-#define GL_SAMPLER_EXTERNAL_OES                                 0x8D66
-#define GL_TEXTURE_BINDING_EXTERNAL_OES                         0x8D67
-#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES                     0x8D68
-#endif
-
 /*------------------------------------------------------------------------*
  * AMD extension tokens
  *------------------------------------------------------------------------*/
@@ -243,6 +243,34 @@
 /* GL_APPLE_texture_2D_limited_npot */
 /* No new tokens introduced by this extension. */
 
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE                           0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE             0x8D56
+#define GL_MAX_SAMPLES_APPLE                                    0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE                               0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE                               0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE                       0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE                       0x8CAA
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT                                             0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE                              0x813D
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
 /*------------------------------------------------------------------------*
  * EXT extension tokens
  *------------------------------------------------------------------------*/
@@ -260,6 +288,14 @@
 #define GL_STENCIL_EXT                                          0x1802
 #endif
 
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT           0x8D6C
+#define GL_RENDERBUFFER_SAMPLES_EXT                             0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT               0x9134
+#define GL_MAX_SAMPLES_EXT                                      0x9135
+#endif
+
 /* GL_EXT_multi_draw_arrays */
 /* No new tokens introduced by this extension. */
 
@@ -270,6 +306,32 @@
 #define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT                       0x8366
 #endif
 
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+/* reuse GL_NO_ERROR */
+#define GL_GUILTY_CONTEXT_RESET_EXT                             0x8253
+#define GL_INNOCENT_CONTEXT_RESET_EXT                           0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_EXT                            0x8255
+#define GL_CONTEXT_ROBUST_ACCESS_EXT                            0x90F3
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT                      0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_EXT                            0x8252
+#define GL_NO_RESET_NOTIFICATION_EXT                            0x8261
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_SRGB_EXT                                             0x8C40
+#define GL_SRGB_ALPHA_EXT                                       0x8C42
+#define GL_SRGB8_ALPHA8_EXT                                     0x8C43
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT            0x8210
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT                         0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT                        0x83F1
+#endif
+
 /* GL_EXT_texture_filter_anisotropic */
 #ifndef GL_EXT_texture_filter_anisotropic
 #define GL_TEXTURE_MAX_ANISOTROPY_EXT                           0x84FE
@@ -288,6 +350,27 @@
 #define GL_TEXTURE_LOD_BIAS_EXT                                 0x8501
 #endif
 
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT                         0x912F
+#define GL_ALPHA8_EXT                                           0x803C  
+#define GL_LUMINANCE8_EXT                                       0x8040
+#define GL_LUMINANCE8_ALPHA8_EXT                                0x8045
+#define GL_RGBA32F_EXT                                          0x8814  
+#define GL_RGB32F_EXT                                           0x8815
+#define GL_ALPHA32F_EXT                                         0x8816
+#define GL_LUMINANCE32F_EXT                                     0x8818
+#define GL_LUMINANCE_ALPHA32F_EXT                               0x8819
+/* reuse GL_RGBA16F_EXT */
+#define GL_RGB16F_EXT                                           0x881B
+#define GL_ALPHA16F_EXT                                         0x881C
+#define GL_LUMINANCE16F_EXT                                     0x881E
+#define GL_LUMINANCE_ALPHA16F_EXT                               0x881F
+#define GL_RGB10_A2_EXT                                         0x8059  
+#define GL_RGB10_EXT                                            0x8052
+#define GL_BGRA8_EXT                                            0x93A1
+#endif
+
 /*------------------------------------------------------------------------*
  * IMG extension tokens
  *------------------------------------------------------------------------*/
@@ -507,6 +590,12 @@
 typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
 #endif
 
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
 /* GL_OES_element_index_uint */
 #ifndef GL_OES_element_index_uint
 #define GL_OES_element_index_uint 1
@@ -785,11 +874,6 @@
 typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
 #endif
 
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_OES_EGL_image_external 1
-#endif
-
 /*------------------------------------------------------------------------*
  * AMD extension functions
  *------------------------------------------------------------------------*/
@@ -813,6 +897,36 @@
 #define GL_APPLE_texture_2D_limited_npot 1
 #endif
 
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 1
+#endif
+
 /*------------------------------------------------------------------------*
  * EXT extension functions
  *------------------------------------------------------------------------*/
@@ -831,6 +945,17 @@
 typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
 #endif
 
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_EXT_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
 /* GL_EXT_multi_draw_arrays */
 #ifndef GL_EXT_multi_draw_arrays
 #define GL_EXT_multi_draw_arrays 1
@@ -847,6 +972,31 @@
 #define GL_EXT_read_format_bgra 1
 #endif
 
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+#define GL_EXT_robustness 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
+GL_API void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GL_API void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params);
+GL_API void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_EXT_sRGB 1
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 1
+#endif
+
 /* GL_EXT_texture_filter_anisotropic */
 #ifndef GL_EXT_texture_filter_anisotropic
 #define GL_EXT_texture_filter_anisotropic 1
@@ -862,6 +1012,25 @@
 #define GL_EXT_texture_lod_bias 1
 #endif
 
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_EXT_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_API void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_API void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_API void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
 /*------------------------------------------------------------------------*
  * IMG extension functions
  *------------------------------------------------------------------------*/
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
index 9db4e252c..8f8d80a 100644
--- a/opengl/include/GLES2/gl2ext.h
+++ b/opengl/include/GLES2/gl2ext.h
@@ -1,7 +1,7 @@
 #ifndef __gl2ext_h_
 #define __gl2ext_h_
 
-/* $Revision: 10969 $ on $Date:: 2010-04-09 02:27:15 -0700 #$ */
+/* $Revision: 16619 $ on $Date:: 2012-01-18 10:00:14 -0800 #$ */
 
 #ifdef __cplusplus
 extern "C" {
@@ -57,6 +57,15 @@
 typedef void* GLeglImageOES;
 #endif
 
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
+#define GL_SAMPLER_EXTERNAL_OES                                 0x8D66
+#define GL_TEXTURE_BINDING_EXTERNAL_OES                         0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES                     0x8D68
+#endif
+
 /* GL_OES_element_index_uint */
 #ifndef GL_OES_element_index_uint
 #define GL_UNSIGNED_INT                                         0x1405
@@ -146,14 +155,6 @@
 #define GL_INT_10_10_10_2_OES                                   0x8DF7
 #endif
 
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
-#define GL_SAMPLER_EXTERNAL_OES                                 0x8D66
-#define GL_TEXTURE_BINDING_EXTERNAL_OES                         0x8D67
-#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES                     0x8D68
-#endif
-
 /*------------------------------------------------------------------------*
  * AMD extension tokens
  *------------------------------------------------------------------------*/
@@ -188,6 +189,69 @@
 #endif
 
 /*------------------------------------------------------------------------*
+ * ANGLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_ANGLE                               0x8CA8
+#define GL_DRAW_FRAMEBUFFER_ANGLE                               0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE                       0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_ANGLE                       0x8CAA
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_ANGLE                           0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE             0x8D56
+#define GL_MAX_SAMPLES_ANGLE                                    0x8D57
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_RGB_422_APPLE                                        0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE                             0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE                         0x85BB
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE                           0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE             0x8D56
+#define GL_MAX_SAMPLES_APPLE                                    0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE                               0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE                               0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE                       0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE                       0x8CAA
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT                                             0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE                              0x813D
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_MALI_SHADER_BINARY_ARM                               0x8F60
+#endif
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
  * EXT extension tokens
  *------------------------------------------------------------------------*/
 
@@ -197,6 +261,29 @@
 #define GL_MAX_EXT                                              0x8008
 #endif
 
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_RGBA16F_EXT                                          0x881A
+#define GL_RGB16F_EXT                                           0x881B
+#define GL_RG16F_EXT                                            0x822F
+#define GL_R16F_EXT                                             0x822D
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT            0x8211
+#define GL_UNSIGNED_NORMALIZED_EXT                              0x8C17
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_PROGRAM_PIPELINE_OBJECT_EXT                          0x8A4F
+#define GL_PROGRAM_OBJECT_EXT                                   0x8B40
+#define GL_SHADER_OBJECT_EXT                                    0x8B48
+#define GL_BUFFER_OBJECT_EXT                                    0x9151
+#define GL_QUERY_OBJECT_EXT                                     0x9153
+#define GL_VERTEX_ARRAY_OBJECT_EXT                              0x9154
+#endif
+
+/* GL_EXT_debug_marker */
+/* No new tokens introduced by this extension. */
+
 /* GL_EXT_discard_framebuffer */
 #ifndef GL_EXT_discard_framebuffer
 #define GL_COLOR_EXT                                            0x1800
@@ -204,9 +291,26 @@
 #define GL_STENCIL_EXT                                          0x1802
 #endif
 
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT           0x8D6C
+#define GL_RENDERBUFFER_SAMPLES_EXT                             0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT               0x9134
+#define GL_MAX_SAMPLES_EXT                                      0x9135
+#endif
+
 /* GL_EXT_multi_draw_arrays */
 /* No new tokens introduced by this extension. */
 
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_ANY_SAMPLES_PASSED_EXT                               0x8C2F
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT                  0x8D6A
+#define GL_CURRENT_QUERY_EXT                                    0x8865
+#define GL_QUERY_RESULT_EXT                                     0x8866
+#define GL_QUERY_RESULT_AVAILABLE_EXT                           0x8867
+#endif
+
 /* GL_EXT_read_format_bgra */
 #ifndef GL_EXT_read_format_bgra
 #define GL_BGRA_EXT                                             0x80E1
@@ -214,6 +318,53 @@
 #define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT                       0x8366
 #endif
 
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+/* reuse GL_NO_ERROR */
+#define GL_GUILTY_CONTEXT_RESET_EXT                             0x8253
+#define GL_INNOCENT_CONTEXT_RESET_EXT                           0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_EXT                            0x8255
+#define GL_CONTEXT_ROBUST_ACCESS_EXT                            0x90F3
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT                      0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_EXT                            0x8252
+#define GL_NO_RESET_NOTIFICATION_EXT                            0x8261
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_VERTEX_SHADER_BIT_EXT                                0x00000001
+#define GL_FRAGMENT_SHADER_BIT_EXT                              0x00000002
+#define GL_ALL_SHADER_BITS_EXT                                  0xFFFFFFFF
+#define GL_PROGRAM_SEPARABLE_EXT                                0x8258
+#define GL_ACTIVE_PROGRAM_EXT                                   0x8259
+#define GL_PROGRAM_PIPELINE_BINDING_EXT                         0x825A
+#endif
+
+/* GL_EXT_shader_texture_lod */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_TEXTURE_COMPARE_MODE_EXT                             0x884C
+#define GL_TEXTURE_COMPARE_FUNC_EXT                             0x884D
+#define GL_COMPARE_REF_TO_TEXTURE_EXT                           0x884E
+#define GL_SAMPLER_2D_SHADOW_EXT                                0x8B62
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_SRGB_EXT                                             0x8C40
+#define GL_SRGB_ALPHA_EXT                                       0x8C42
+#define GL_SRGB8_ALPHA8_EXT                                     0x8C43
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT            0x8210
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT                         0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT                        0x83F1
+#endif
+
 /* GL_EXT_texture_filter_anisotropic */
 #ifndef GL_EXT_texture_filter_anisotropic
 #define GL_TEXTURE_MAX_ANISOTROPY_EXT                           0x84FE
@@ -225,15 +376,54 @@
 #define GL_BGRA_EXT                                             0x80E1
 #endif
 
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_RED_EXT                                              0x1903
+#define GL_RG_EXT                                               0x8227
+#define GL_R8_EXT                                               0x8229
+#define GL_RG8_EXT                                              0x822B
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT                         0x912F
+#define GL_ALPHA8_EXT                                           0x803C  
+#define GL_LUMINANCE8_EXT                                       0x8040
+#define GL_LUMINANCE8_ALPHA8_EXT                                0x8045
+#define GL_RGBA32F_EXT                                          0x8814  
+#define GL_RGB32F_EXT                                           0x8815
+#define GL_ALPHA32F_EXT                                         0x8816
+#define GL_LUMINANCE32F_EXT                                     0x8818
+#define GL_LUMINANCE_ALPHA32F_EXT                               0x8819
+/* reuse GL_RGBA16F_EXT */
+#define GL_RGB16F_EXT                                           0x881B
+#define GL_ALPHA16F_EXT                                         0x881C
+#define GL_LUMINANCE16F_EXT                                     0x881E
+#define GL_LUMINANCE_ALPHA16F_EXT                               0x881F
+#define GL_RGB10_A2_EXT                                         0x8059  
+#define GL_RGB10_EXT                                            0x8052
+#define GL_BGRA8_EXT                                            0x93A1
+#endif
+
 /* GL_EXT_texture_type_2_10_10_10_REV */
 #ifndef GL_EXT_texture_type_2_10_10_10_REV
 #define GL_UNSIGNED_INT_2_10_10_10_REV_EXT                      0x8368
 #endif
 
-/* GL_EXT_texture_compression_dxt1 */
-#ifndef GL_EXT_texture_compression_dxt1
-#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT                         0x83F0
-#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT                        0x83F1
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_UNPACK_ROW_LENGTH                                    0x0CF2
+#define GL_UNPACK_SKIP_ROWS                                     0x0CF3
+#define GL_UNPACK_SKIP_PIXELS                                   0x0CF4
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_SHADER_BINARY_DMP                                    0x9250
 #endif
 
 /*------------------------------------------------------------------------*
@@ -276,13 +466,6 @@
  * NV extension tokens
  *------------------------------------------------------------------------*/
 
-/* GL_NV_fence */
-#ifndef GL_NV_fence
-#define GL_ALL_COMPLETED_NV                                     0x84F2
-#define GL_FENCE_STATUS_NV                                      0x84F3
-#define GL_FENCE_CONDITION_NV                                   0x84F4
-#endif
-
 /* GL_NV_coverage_sample */
 #ifndef GL_NV_coverage_sample
 #define GL_COVERAGE_COMPONENT_NV                                0x8ED0
@@ -301,10 +484,90 @@
 #define GL_DEPTH_COMPONENT16_NONLINEAR_NV                       0x8E2C
 #endif
 
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_NV                                  0x8824
+#define GL_DRAW_BUFFER0_NV                                      0x8825
+#define GL_DRAW_BUFFER1_NV                                      0x8826
+#define GL_DRAW_BUFFER2_NV                                      0x8827
+#define GL_DRAW_BUFFER3_NV                                      0x8828
+#define GL_DRAW_BUFFER4_NV                                      0x8829
+#define GL_DRAW_BUFFER5_NV                                      0x882A
+#define GL_DRAW_BUFFER6_NV                                      0x882B
+#define GL_DRAW_BUFFER7_NV                                      0x882C
+#define GL_DRAW_BUFFER8_NV                                      0x882D
+#define GL_DRAW_BUFFER9_NV                                      0x882E
+#define GL_DRAW_BUFFER10_NV                                     0x882F
+#define GL_DRAW_BUFFER11_NV                                     0x8830
+#define GL_DRAW_BUFFER12_NV                                     0x8831
+#define GL_DRAW_BUFFER13_NV                                     0x8832
+#define GL_DRAW_BUFFER14_NV                                     0x8833
+#define GL_DRAW_BUFFER15_NV                                     0x8834
+#define GL_COLOR_ATTACHMENT0_NV                                 0x8CE0
+#define GL_COLOR_ATTACHMENT1_NV                                 0x8CE1
+#define GL_COLOR_ATTACHMENT2_NV                                 0x8CE2
+#define GL_COLOR_ATTACHMENT3_NV                                 0x8CE3
+#define GL_COLOR_ATTACHMENT4_NV                                 0x8CE4
+#define GL_COLOR_ATTACHMENT5_NV                                 0x8CE5
+#define GL_COLOR_ATTACHMENT6_NV                                 0x8CE6
+#define GL_COLOR_ATTACHMENT7_NV                                 0x8CE7
+#define GL_COLOR_ATTACHMENT8_NV                                 0x8CE8
+#define GL_COLOR_ATTACHMENT9_NV                                 0x8CE9
+#define GL_COLOR_ATTACHMENT10_NV                                0x8CEA
+#define GL_COLOR_ATTACHMENT11_NV                                0x8CEB
+#define GL_COLOR_ATTACHMENT12_NV                                0x8CEC
+#define GL_COLOR_ATTACHMENT13_NV                                0x8CED
+#define GL_COLOR_ATTACHMENT14_NV                                0x8CEE
+#define GL_COLOR_ATTACHMENT15_NV                                0x8CEF
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_MAX_COLOR_ATTACHMENTS_NV                             0x8CDF
+/* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV                                     0x84F2
+#define GL_FENCE_STATUS_NV                                      0x84F3
+#define GL_FENCE_CONDITION_NV                                   0x84F4
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_READ_BUFFER_NV                                       0x0C02
+#endif
+
+/* GL_NV_read_buffer_front */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_compression_s3tc_update */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_npot_2D_mipmap */
+/* No new tokens introduced by this extension. */
+
 /*------------------------------------------------------------------------*
  * QCOM extension tokens
  *------------------------------------------------------------------------*/
 
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_ALPHA_TEST_QCOM                                      0x0BC0
+#define GL_ALPHA_TEST_FUNC_QCOM                                 0x0BC1
+#define GL_ALPHA_TEST_REF_QCOM                                  0x0BC2
+#endif
+
 /* GL_QCOM_driver_control */
 /* No new tokens introduced by this extension. */
 
@@ -373,6 +636,15 @@
 #endif
 
 /*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_SHADER_BINARY_VIV                                    0x8FC4
+#endif
+
+/*------------------------------------------------------------------------*
  * End of extension tokens, start of corresponding extension functions
  *------------------------------------------------------------------------*/
 
@@ -416,6 +688,12 @@
 typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
 #endif
 
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
 /* GL_OES_element_index_uint */
 #ifndef GL_OES_element_index_uint
 #define GL_OES_element_index_uint 1
@@ -549,11 +827,6 @@
 #define GL_OES_vertex_type_10_10_10_2 1
 #endif
 
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_OES_EGL_image_external 1
-#endif
-
 /*------------------------------------------------------------------------*
  * AMD extension functions
  *------------------------------------------------------------------------*/
@@ -603,6 +876,72 @@
 #endif
 
 /*------------------------------------------------------------------------*
+ * ANGLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_ANGLE_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_ANGLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_ARM_mali_shader_binary 1
+#endif
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 1
+#endif
+
+/*------------------------------------------------------------------------*
  * EXT extension functions
  *------------------------------------------------------------------------*/
 
@@ -611,6 +950,35 @@
 #define GL_EXT_blend_minmax 1
 #endif
 
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_EXT_color_buffer_half_float 1
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_EXT_debug_label 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+
+/* GL_EXT_debug_marker */
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void);
+#endif
+typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#endif
+
 /* GL_EXT_discard_framebuffer */
 #ifndef GL_EXT_discard_framebuffer
 #define GL_EXT_discard_framebuffer 1
@@ -620,6 +988,17 @@
 typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
 #endif
 
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_EXT_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
 #ifndef GL_EXT_multi_draw_arrays
 #define GL_EXT_multi_draw_arrays 1
 #ifdef GL_GLEXT_PROTOTYPES
@@ -630,11 +1009,134 @@
 typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
 #endif
 
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_EXT_occlusion_query_boolean 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids);
+GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids);
+GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id);
+GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id);
+GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target);
+GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params);
+#endif
+typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
+typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id);
+typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
+typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
 /* GL_EXT_read_format_bgra */
 #ifndef GL_EXT_read_format_bgra
 #define GL_EXT_read_format_bgra 1
 #endif
 
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+#define GL_EXT_robustness 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
+GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params);
+GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_EXT_separate_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program);
+GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program);
+GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings);
+GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines);
+GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines);
+GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
+typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
+typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
+typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint x, GLint y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+
+/* GL_EXT_shader_texture_lod */
+#ifndef GL_EXT_shader_texture_lod
+#define GL_EXT_shader_texture_lod 1
+#endif
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_EXT_shadow_samplers 1
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_EXT_sRGB 1
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 1
+#endif
+
 /* GL_EXT_texture_filter_anisotropic */
 #ifndef GL_EXT_texture_filter_anisotropic
 #define GL_EXT_texture_filter_anisotropic 1
@@ -645,14 +1147,47 @@
 #define GL_EXT_texture_format_BGRA8888 1
 #endif
 
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_EXT_texture_rg 1
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_EXT_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
 /* GL_EXT_texture_type_2_10_10_10_REV */
 #ifndef GL_EXT_texture_type_2_10_10_10_REV
 #define GL_EXT_texture_type_2_10_10_10_REV 1
 #endif
 
-/* GL_EXT_texture_compression_dxt1 */
-#ifndef GL_EXT_texture_compression_dxt1
-#define GL_EXT_texture_compression_dxt1 1
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_EXT_unpack_subimage 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_DMP_shader_binary 1
 #endif
 
 /*------------------------------------------------------------------------*
@@ -694,6 +1229,36 @@
  * NV extension functions
  *------------------------------------------------------------------------*/
 
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_NV_coverage_sample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
+GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
+typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_NV_depth_nonlinear 1
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_NV_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_NV_fbo_color_attachments 1
+#endif
+
 /* GL_NV_fence */
 #ifndef GL_NV_fence
 #define GL_NV_fence 1
@@ -715,26 +1280,58 @@
 typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
 #endif
 
-/* GL_NV_coverage_sample */
-#ifndef GL_NV_coverage_sample
-#define GL_NV_coverage_sample 1
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_NV_read_buffer 1
 #ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
-GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode);
 #endif
-typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
-typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode);
 #endif
 
-/* GL_NV_depth_nonlinear */
-#ifndef GL_NV_depth_nonlinear
-#define GL_NV_depth_nonlinear 1
+/* GL_NV_read_buffer_front */
+#ifndef GL_NV_read_buffer_front
+#define GL_NV_read_buffer_front 1
+#endif
+
+/* GL_NV_read_depth */
+#ifndef GL_NV_read_depth
+#define GL_NV_read_depth 1
+#endif
+
+/* GL_NV_read_depth_stencil */
+#ifndef GL_NV_read_depth_stencil
+#define GL_NV_read_depth_stencil 1
+#endif
+
+/* GL_NV_read_stencil */
+#ifndef GL_NV_read_stencil
+#define GL_NV_read_stencil 1
+#endif
+
+/* GL_NV_texture_compression_s3tc_update */
+#ifndef GL_NV_texture_compression_s3tc_update
+#define GL_NV_texture_compression_s3tc_update 1
+#endif
+
+/* GL_NV_texture_npot_2D_mipmap */
+#ifndef GL_NV_texture_npot_2D_mipmap
+#define GL_NV_texture_npot_2D_mipmap 1
 #endif
 
 /*------------------------------------------------------------------------*
  * QCOM extension functions
  *------------------------------------------------------------------------*/
 
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_QCOM_alpha_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref);
+#endif
+
 /* GL_QCOM_driver_control */
 #ifndef GL_QCOM_driver_control
 #define GL_QCOM_driver_control 1
@@ -809,6 +1406,15 @@
 typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
 #endif
 
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_VIV_shader_binary 1
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 2fc6125..0b1016c 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -118,12 +118,6 @@
 
 // ----------------------------------------------------------------------------
 
-Loader::entry_t::entry_t(int dpy, int impl, const char* tag)
-    : dpy(dpy), impl(impl), tag(tag) {
-}
-
-// ----------------------------------------------------------------------------
-
 Loader::Loader()
 {
     char line[256];
@@ -131,8 +125,9 @@
 
     /* Special case for GLES emulation */
     if (checkGlesEmulationStatus() == 0) {
-        ALOGD("Emulator without GPU support detected. Fallback to software renderer.");
-        gConfig.add( entry_t(0, 0, "android") );
+        ALOGD("Emulator without GPU support detected. "
+              "Fallback to software renderer.");
+        mDriverTag.setTo("android");
         return;
     }
 
@@ -141,14 +136,16 @@
     if (cfg == NULL) {
         // default config
         ALOGD("egl.cfg not found, using default config");
-        gConfig.add( entry_t(0, 0, "android") );
+        mDriverTag.setTo("android");
     } else {
         while (fgets(line, 256, cfg)) {
-            int dpy;
-            int impl;
+            int dpy, impl;
             if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) {
                 //ALOGD(">>> %u %u %s", dpy, impl, tag);
-                gConfig.add( entry_t(dpy, impl, tag) );
+                // We only load the h/w accelerated implementation
+                if (tag != String8("android")) {
+                    mDriverTag = tag;
+                }
             }
         }
         fclose(cfg);
@@ -160,30 +157,12 @@
     GLTrace_stop();
 }
 
-const char* Loader::getTag(int dpy, int impl)
+void* Loader::open(egl_connection_t* cnx)
 {
-    const Vector<entry_t>& cfgs(gConfig);    
-    const size_t c = cfgs.size();
-    for (size_t i=0 ; i<c ; i++) {
-        if (dpy == cfgs[i].dpy)
-            if (impl == cfgs[i].impl)
-                return cfgs[i].tag.string();
-    }
-    return 0;
-}
-
-void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx)
-{
-    /*
-     * TODO: if we don't find display/0, then use 0/0
-     * (0/0 should always work)
-     */
-    
     void* dso;
-    int index = int(display);
     driver_t* hnd = 0;
     
-    char const* tag = getTag(index, impl);
+    char const* tag = mDriverTag.string();
     if (tag) {
         dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2);
         if (dso) {
@@ -193,16 +172,14 @@
             dso = load_driver("EGL", tag, cnx, EGL);
             if (dso) {
                 hnd = new driver_t(dso);
-
                 // TODO: make this more automated
                 hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM );
-
-                hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 );
+                hnd->set( load_driver("GLESv2",    tag, cnx, GLESv2),    GLESv2 );
             }
         }
     }
 
-    LOG_FATAL_IF(!index && !impl && !hnd, 
+    LOG_FATAL_IF(!index && !hnd,
             "couldn't find the default OpenGL ES implementation "
             "for default display");
     
@@ -221,7 +198,7 @@
         __eglMustCastToProperFunctionPointerType* curr, 
         getProcAddressType getProcAddress) 
 {
-    const size_t SIZE = 256;
+    const ssize_t SIZE = 256;
     char scrap[SIZE];
     while (*api) {
         char const * name = *api;
@@ -253,6 +230,19 @@
         if (f == NULL) {
             //ALOGD("%s", name);
             f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
+
+            /*
+             * GL_EXT_debug_label is special, we always report it as
+             * supported, it's handled by GLES_trace. If GLES_trace is not
+             * enabled, then these are no-ops.
+             */
+            if (!strcmp(name, "glInsertEventMarkerEXT")) {
+                f = (__eglMustCastToProperFunctionPointerType)gl_noop;
+            } else if (!strcmp(name, "glPushGroupMarkerEXT")) {
+                f = (__eglMustCastToProperFunctionPointerType)gl_noop;
+            } else if (!strcmp(name, "glPopGroupMarkerEXT")) {
+                f = (__eglMustCastToProperFunctionPointerType)gl_noop;
+            }
         }
         *curr++ = f;
         api++;
@@ -313,14 +303,14 @@
     if (mask & GLESv1_CM) {
         init_api(dso, gl_names,
             (__eglMustCastToProperFunctionPointerType*)
-                &cnx->hooks[GLESv1_INDEX]->gl,
+                &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl,
             getProcAddress);
     }
 
     if (mask & GLESv2) {
       init_api(dso, gl_names,
             (__eglMustCastToProperFunctionPointerType*)
-                &cnx->hooks[GLESv2_INDEX]->gl,
+                &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
             getProcAddress);
     }
     
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 580d6e4..30773cb 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -24,7 +24,6 @@
 #include <utils/Errors.h>
 #include <utils/Singleton.h>
 #include <utils/String8.h>
-#include <utils/Vector.h>
 
 #include <EGL/egl.h>
 
@@ -53,23 +52,13 @@
         void* dso[3];
     };
     
-    struct entry_t {
-        entry_t() { }
-        entry_t(int dpy, int impl, const char* tag);
-        int dpy;
-        int impl;
-        String8 tag;
-    };
-
-    Vector<entry_t> gConfig;    
+    String8 mDriverTag;
     getProcAddressType getProcAddress;
     
-    const char* getTag(int dpy, int impl);
-
 public:
     ~Loader();
     
-    void* open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx);
+    void* open(egl_connection_t* cnx);
     status_t close(void* driver);
     
 private:
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index e053589..4a56dcf 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -48,8 +48,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
-egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
-gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+egl_connection_t gEGLImpl;
+gl_hooks_t gHooks[2];
 gl_hooks_t gHooksNoContext;
 pthread_key_t gGLWrapperKey = -1;
 
@@ -187,16 +187,13 @@
     return dp;
 }
 
-egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig config,
+egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig,
         egl_display_t const*& dp) {
     dp = validate_display(dpy);
     if (!dp)
         return (egl_connection_t*) NULL;
 
-    if (intptr_t(config) >= dp->numTotalConfigs) {
-        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
-    }
-    egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(config)].impl];
+    egl_connection_t* const cnx = &gEGLImpl;
     if (cnx->dso == 0) {
         return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
     }
@@ -228,7 +225,27 @@
     // EGL.
 
     egl_image_t const * const i = get_image(image);
-    return i->images[c->impl];
+    return i->image;
+}
+
+// ----------------------------------------------------------------------------
+
+const GLubyte * egl_get_string_for_current_context(GLenum name) {
+    // NOTE: returning NULL here will fall-back to the default
+    // implementation.
+
+    EGLContext context = egl_tls_t::getContext();
+    if (context == EGL_NO_CONTEXT)
+        return NULL;
+
+    egl_context_t const * const c = get_context(context);
+    if (c == NULL) // this should never happen, by construction
+        return NULL;
+
+    if (name != GL_EXTENSIONS)
+        return NULL;
+
+    return (const GLubyte *)c->gl_extensions.string();
 }
 
 // ----------------------------------------------------------------------------
@@ -246,34 +263,17 @@
     // get our driver loader
     Loader& loader(Loader::getInstance());
 
-    // dynamically load all our EGL implementations
-    egl_connection_t* cnx;
-
-    cnx = &gEGLImpl[IMPL_SOFTWARE];
+    // dynamically load our EGL implementation
+    egl_connection_t* cnx = &gEGLImpl;
     if (cnx->dso == 0) {
-        cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
-        cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
-        cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
+        cnx->hooks[egl_connection_t::GLESv1_INDEX] =
+                &gHooks[egl_connection_t::GLESv1_INDEX];
+        cnx->hooks[egl_connection_t::GLESv2_INDEX] =
+                &gHooks[egl_connection_t::GLESv2_INDEX];
+        cnx->dso = loader.open(cnx);
     }
 
-    cnx = &gEGLImpl[IMPL_HARDWARE];
-    if (cnx->dso == 0) {
-        char value[PROPERTY_VALUE_MAX];
-        property_get("debug.egl.hw", value, "1");
-        if (atoi(value) != 0) {
-            cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
-            cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
-            cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
-        } else {
-            ALOGD("3D hardware acceleration is disabled");
-        }
-    }
-
-    if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
-        return EGL_FALSE;
-    }
-
-    return EGL_TRUE;
+    return cnx->dso ? EGL_TRUE : EGL_FALSE;
 }
 
 static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
@@ -290,6 +290,9 @@
     ALOGE("called unimplemented OpenGL ES API");
 }
 
+void gl_noop() {
+}
+
 // ----------------------------------------------------------------------------
 
 #if USE_FAST_TLS_KEY
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 664f258..bb2783d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -44,6 +44,7 @@
 #include "egl_impl.h"
 #include "egl_object.h"
 #include "egl_tls.h"
+#include "egldefs.h"
 
 using namespace android;
 
@@ -88,24 +89,6 @@
 
 // ----------------------------------------------------------------------------
 
-template<typename T>
-static __attribute__((noinline))
-int binarySearch(T const sortedArray[], int first, int last, T key) {
-    while (first <= last) {
-        int mid = (first + last) / 2;
-        if (sortedArray[mid] < key) {
-            first = mid + 1;
-        } else if (key < sortedArray[mid]) {
-            last = mid - 1;
-        } else {
-            return mid;
-        }
-    }
-    return -1;
-}
-
-// ----------------------------------------------------------------------------
-
 namespace android {
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 extern EGLBoolean egl_init_drivers();
@@ -183,21 +166,20 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    GLint numConfigs = dp->numTotalConfigs;
-    if (!configs) {
-        *num_config = numConfigs;
-        return EGL_TRUE;
+    if (num_config==0) {
+        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
     }
 
-    GLint n = 0;
-    for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
-        *configs++ = EGLConfig(i);
-        config_size--;
-        n++;
+    EGLBoolean res = EGL_FALSE;
+    *num_config = 0;
+
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso) {
+        res = cnx->egl.eglGetConfigs(
+                dp->disp.dpy, configs, config_size, num_config);
     }
-    
-    *num_config = n;
-    return EGL_TRUE;
+
+    return res;
 }
 
 EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
@@ -213,105 +195,13 @@
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
     }
 
-    EGLint n;
     EGLBoolean res = EGL_FALSE;
     *num_config = 0;
 
-    
-    // It is unfortunate, but we need to remap the EGL_CONFIG_IDs, 
-    // to do this, we have to go through the attrib_list array once
-    // to figure out both its size and if it contains an EGL_CONFIG_ID
-    // key. If so, the full array is copied and patched.
-    // NOTE: we assume that there can be only one occurrence
-    // of EGL_CONFIG_ID.
-    
-    EGLint patch_index = -1;
-    GLint attr;
-    size_t size = 0;
-    if (attrib_list) {
-        while ((attr=attrib_list[size]) != EGL_NONE) {
-            if (attr == EGL_CONFIG_ID)
-                patch_index = size;
-            size += 2;
-        }
-    }
-    if (patch_index >= 0) {
-        size += 2; // we need copy the sentinel as well
-        EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
-        if (new_list == 0)
-            return setError(EGL_BAD_ALLOC, EGL_FALSE);
-        memcpy(new_list, attrib_list, size*sizeof(EGLint));
-
-        // patch the requested EGL_CONFIG_ID
-        bool found = false;
-        EGLConfig ourConfig(0);
-        EGLint& configId(new_list[patch_index+1]);
-        for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
-            if (dp->configs[i].configId == configId) {
-                ourConfig = EGLConfig(i);
-                configId = dp->configs[i].implConfigId;
-                found = true;
-                break;
-            }
-        }
-
-        egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
-        if (found && cnx->dso) {
-            // and switch to the new list
-            attrib_list = const_cast<const EGLint *>(new_list);
-
-            // At this point, the only configuration that can match is
-            // dp->configs[i][index], however, we don't know if it would be
-            // rejected because of the other attributes, so we do have to call
-            // cnx->egl.eglChooseConfig() -- but we don't have to loop
-            // through all the EGLimpl[].
-            // We also know we can only get a single config back, and we know
-            // which one.
-
-            res = cnx->egl.eglChooseConfig(
-                    dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
-                    attrib_list, configs, config_size, &n);
-            if (res && n>0) {
-                // n has to be 0 or 1, by construction, and we already know
-                // which config it will return (since there can be only one).
-                if (configs) {
-                    configs[0] = ourConfig;
-                }
-                *num_config = 1;
-            }
-        }
-
-        free(const_cast<EGLint *>(attrib_list));
-        return res;
-    }
-
-
-    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso) {
-            if (cnx->egl.eglChooseConfig(
-                    dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
-                if (configs) {
-                    // now we need to convert these client EGLConfig to our
-                    // internal EGLConfig format.
-                    // This is done in O(n Log(n)) time.
-                    for (int j=0 ; j<n ; j++) {
-                        egl_config_t key(i, configs[j]);
-                        intptr_t index = binarySearch<egl_config_t>(
-                                dp->configs, 0, dp->numTotalConfigs, key);
-                        if (index >= 0) {
-                            configs[j] = EGLConfig(index);
-                        } else {
-                            return setError(EGL_BAD_CONFIG, EGL_FALSE);
-                        }
-                    }
-                    configs += n;
-                    config_size -= n;
-                }
-                *num_config += n;
-                res = EGL_TRUE;
-            }
-        }
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso) {
+        res = cnx->egl.eglChooseConfig(
+                dp->disp.dpy, attrib_list, configs, config_size, num_config);
     }
     return res;
 }
@@ -325,13 +215,8 @@
     egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (!cnx) return EGL_FALSE;
     
-    if (attribute == EGL_CONFIG_ID) {
-        *value = dp->configs[intptr_t(config)].configId;
-        return EGL_TRUE;
-    }
     return cnx->egl.eglGetConfigAttrib(
-            dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
-            dp->configs[intptr_t(config)].config, attribute, value);
+            dp->disp.dpy, config, attribute, value);
 }
 
 // ----------------------------------------------------------------------------
@@ -347,8 +232,7 @@
     egl_display_t const* dp = 0;
     egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (cnx) {
-        EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy;
-        EGLConfig iConfig = dp->configs[intptr_t(config)].config;
+        EGLDisplay iDpy = dp->disp.dpy;
         EGLint format;
 
         if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
@@ -359,7 +243,7 @@
 
         // set the native window's buffers format to match this config
         if (cnx->egl.eglGetConfigAttrib(iDpy,
-                iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
+                config, EGL_NATIVE_VISUAL_ID, &format)) {
             if (format != 0) {
                 int err = native_window_set_buffers_format(window, format);
                 if (err != 0) {
@@ -377,10 +261,9 @@
         anw->setSwapInterval(anw, 1);
 
         EGLSurface surface = cnx->egl.eglCreateWindowSurface(
-                iDpy, iConfig, window, attrib_list);
+                iDpy, config, window, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
-                    dp->configs[intptr_t(config)].impl, cnx);
+            egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, cnx);
             return s;
         }
 
@@ -401,11 +284,9 @@
     egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (cnx) {
         EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
-                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
-                dp->configs[intptr_t(config)].config, pixmap, attrib_list);
+                dp->disp.dpy, config, pixmap, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
-                    dp->configs[intptr_t(config)].impl, cnx);
+            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
             return s;
         }
     }
@@ -421,11 +302,9 @@
     egl_connection_t* cnx = validate_display_config(dpy, config, dp);
     if (cnx) {
         EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
-                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
-                dp->configs[intptr_t(config)].config, attrib_list);
+                dp->disp.dpy, config, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
-                    dp->configs[intptr_t(config)].impl, cnx);
+            egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx);
             return s;
         }
     }
@@ -444,8 +323,7 @@
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     egl_surface_t * const s = get_surface(surface);
-    EGLBoolean result = s->cnx->egl.eglDestroySurface(
-            dp->disp[s->impl].dpy, s->surface);
+    EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
     if (result == EGL_TRUE) {
         _s.terminate();
     }
@@ -465,16 +343,28 @@
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     egl_surface_t const * const s = get_surface(surface);
-    EGLBoolean result(EGL_TRUE);
-    if (attribute == EGL_CONFIG_ID) {
-        // We need to remap EGL_CONFIG_IDs
-        *value = dp->configs[intptr_t(s->config)].configId;
-    } else {
-        result = s->cnx->egl.eglQuerySurface(
-                dp->disp[s->impl].dpy, s->surface, attribute, value);
+    return s->cnx->egl.eglQuerySurface(
+            dp->disp.dpy, s->surface, attribute, value);
+}
+
+void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
+    clearError();
+
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) {
+        return;
     }
 
-    return result;
+    SurfaceRef _s(dp, surface);
+    if (!_s.get()) {
+        setError(EGL_BAD_SURFACE, EGL_FALSE);
+        return;
+    }
+
+    int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+
+    egl_surface_t const * const s = get_surface(surface);
+    native_window_set_buffers_timestamp(s->win.get(), timestamp);
 }
 
 // ----------------------------------------------------------------------------
@@ -494,9 +384,7 @@
             share_list = c->context;
         }
         EGLContext context = cnx->egl.eglCreateContext(
-                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
-                dp->configs[intptr_t(config)].config,
-                share_list, attrib_list);
+                dp->disp.dpy, config, share_list, attrib_list);
         if (context != EGL_NO_CONTEXT) {
             // figure out if it's a GLESv1 or GLESv2
             int version = 0;
@@ -506,15 +394,14 @@
                     GLint value = *attrib_list++;
                     if (attr == EGL_CONTEXT_CLIENT_VERSION) {
                         if (value == 1) {
-                            version = GLESv1_INDEX;
+                            version = egl_connection_t::GLESv1_INDEX;
                         } else if (value == 2) {
-                            version = GLESv2_INDEX;
+                            version = egl_connection_t::GLESv2_INDEX;
                         }
                     }
                 };
             }
-            egl_context_t* c = new egl_context_t(dpy, context, config,
-                    dp->configs[intptr_t(config)].impl, cnx, version);
+            egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version);
 #if EGL_TRACE
             if (gEGLDebugLevel > 0)
                 GLTrace_eglCreateContext(version, c);
@@ -538,35 +425,13 @@
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
     
     egl_context_t * const c = get_context(ctx);
-    EGLBoolean result = c->cnx->egl.eglDestroyContext(
-            dp->disp[c->impl].dpy, c->context);
+    EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
     if (result == EGL_TRUE) {
         _c.terminate();
     }
     return result;
 }
 
-static void loseCurrent(egl_context_t * cur_c)
-{
-    if (cur_c) {
-        egl_surface_t * cur_r = get_surface(cur_c->read);
-        egl_surface_t * cur_d = get_surface(cur_c->draw);
-
-        // by construction, these are either 0 or valid (possibly terminated)
-        // it should be impossible for these to be invalid
-        ContextRef _cur_c(cur_c);
-        SurfaceRef _cur_r(cur_r);
-        SurfaceRef _cur_d(cur_d);
-
-        cur_c->read = NULL;
-        cur_c->draw = NULL;
-
-        _cur_c.release();
-        _cur_r.release();
-        _cur_d.release();
-    }
-}
-
 EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
                             EGLSurface read, EGLContext ctx)
 {
@@ -626,38 +491,22 @@
     // retrieve the underlying implementation's draw EGLSurface
     if (draw != EGL_NO_SURFACE) {
         d = get_surface(draw);
-        // make sure the EGLContext and EGLSurface passed in are for
-        // the same driver
-        if (c && d->impl != c->impl)
-            return setError(EGL_BAD_MATCH, EGL_FALSE);
         impl_draw = d->surface;
     }
 
     // retrieve the underlying implementation's read EGLSurface
     if (read != EGL_NO_SURFACE) {
         r = get_surface(read);
-        // make sure the EGLContext and EGLSurface passed in are for
-        // the same driver
-        if (c && r->impl != c->impl)
-            return setError(EGL_BAD_MATCH, EGL_FALSE);
         impl_read = r->surface;
     }
 
-    EGLBoolean result;
 
-    if (c) {
-        result = c->cnx->egl.eglMakeCurrent(
-                dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
-    } else {
-        result = cur_c->cnx->egl.eglMakeCurrent(
-                dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
-    }
+    EGLBoolean result = const_cast<egl_display_t*>(dp)->makeCurrent(c, cur_c,
+            draw, read, ctx,
+            impl_draw, impl_read, impl_ctx);
 
     if (result == EGL_TRUE) {
-
-        loseCurrent(cur_c);
-
-        if (ctx != EGL_NO_CONTEXT) {
+        if (c) {
             setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
             egl_tls_t::setContext(ctx);
 #if EGL_TRACE
@@ -667,8 +516,6 @@
             _c.acquire();
             _r.acquire();
             _d.acquire();
-            c->read = read;
-            c->draw = draw;
         } else {
             setGLHooksThreadSpecific(&gHooksNoContext);
             egl_tls_t::setContext(EGL_NO_CONTEXT);
@@ -693,17 +540,9 @@
     if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
     egl_context_t * const c = get_context(ctx);
+    return c->cnx->egl.eglQueryContext(
+            dp->disp.dpy, c->context, attribute, value);
 
-    EGLBoolean result(EGL_TRUE);
-    if (attribute == EGL_CONFIG_ID) {
-        *value = dp->configs[intptr_t(c->config)].configId;
-    } else {
-        // We need to remap EGL_CONFIG_IDs
-        result = c->cnx->egl.eglQueryContext(
-                dp->disp[c->impl].dpy, c->context, attribute, value);
-    }
-
-    return result;
 }
 
 EGLContext eglGetCurrentContext(void)
@@ -755,64 +594,37 @@
 
 EGLBoolean eglWaitGL(void)
 {
-    // could be called before eglInitialize(), but we wouldn't have a context
-    // then, and this function would return GL_TRUE, which isn't wrong.
-
     clearError();
 
-    EGLBoolean res = EGL_TRUE;
-    EGLContext ctx = getContext();
-    if (ctx) {
-        egl_context_t const * const c = get_context(ctx);
-        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        if (uint32_t(c->impl)>=2)
-            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        egl_connection_t* const cnx = &gEGLImpl[c->impl];
-        if (!cnx->dso) 
-            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        res = cnx->egl.eglWaitGL();
-    }
-    return res;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (!cnx->dso)
+        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+    return cnx->egl.eglWaitGL();
 }
 
 EGLBoolean eglWaitNative(EGLint engine)
 {
-    // could be called before eglInitialize(), but we wouldn't have a context
-    // then, and this function would return GL_TRUE, which isn't wrong.
-
     clearError();
 
-    EGLBoolean res = EGL_TRUE;
-    EGLContext ctx = getContext();
-    if (ctx) {
-        egl_context_t const * const c = get_context(ctx);
-        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        if (uint32_t(c->impl)>=2)
-            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        egl_connection_t* const cnx = &gEGLImpl[c->impl];
-        if (!cnx->dso) 
-            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        res = cnx->egl.eglWaitNative(engine);
-    }
-    return res;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (!cnx->dso)
+        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+    return cnx->egl.eglWaitNative(engine);
 }
 
 EGLint eglGetError(void)
 {
-    EGLint result = EGL_SUCCESS;
-    EGLint err;
-    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-        err = EGL_SUCCESS;
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso)
-            err = cnx->egl.eglGetError();
-        if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
-            result = err;
+    EGLint err = EGL_SUCCESS;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso) {
+        err = cnx->egl.eglGetError();
     }
-    err = egl_tls_t::getError();
-    if (result == EGL_SUCCESS)
-        result = err;
-    return result;
+    if (err == EGL_SUCCESS) {
+        err = egl_tls_t::getError();
+    }
+    return err;
 }
 
 // Note: Similar implementations of these functions also exist in
@@ -896,19 +708,20 @@
 
         if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
             bool found = false;
-            for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-                egl_connection_t* const cnx = &gEGLImpl[i];
-                if (cnx->dso && cnx->egl.eglGetProcAddress) {
-                    found = true;
-                    // Extensions are independent of the bound context
-                    cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
-                    cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
+
+            egl_connection_t* const cnx = &gEGLImpl;
+            if (cnx->dso && cnx->egl.eglGetProcAddress) {
+                found = true;
+                // Extensions are independent of the bound context
+                cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
+                cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
 #if EGL_TRACE
-                    debugHooks->ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
+                debugHooks->ext.extensions[slot] =
+                gHooksTrace.ext.extensions[slot] =
 #endif
-                            cnx->egl.eglGetProcAddress(procname);
-                }
+                        cnx->egl.eglGetProcAddress(procname);
             }
+
             if (found) {
                 addr = gExtensionForwarders[slot];
 
@@ -947,7 +760,7 @@
 #endif
 
     egl_surface_t const * const s = get_surface(draw);
-    return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
+    return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
 }
 
 EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
@@ -963,8 +776,7 @@
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     egl_surface_t const * const s = get_surface(surface);
-    return s->cnx->egl.eglCopyBuffers(
-            dp->disp[s->impl].dpy, s->surface, target);
+    return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
 }
 
 const char* eglQueryString(EGLDisplay dpy, EGLint name)
@@ -983,12 +795,8 @@
             return dp->getExtensionString();
         case EGL_CLIENT_APIS:
             return dp->getClientApiString();
-        case EGL_VERSION_HW_ANDROID: {
-            if (gEGLImpl[IMPL_HARDWARE].dso) {
-                return dp->disp[IMPL_HARDWARE].queryString.version;
-            }
-            return dp->disp[IMPL_SOFTWARE].queryString.version;
-        }
+        case EGL_VERSION_HW_ANDROID:
+            return dp->disp.queryString.version;
     }
     return setError(EGL_BAD_PARAMETER, (const char *)0);
 }
@@ -1013,7 +821,7 @@
     egl_surface_t const * const s = get_surface(surface);
     if (s->cnx->egl.eglSurfaceAttrib) {
         return s->cnx->egl.eglSurfaceAttrib(
-                dp->disp[s->impl].dpy, s->surface, attribute, value);
+                dp->disp.dpy, s->surface, attribute, value);
     }
     return setError(EGL_BAD_SURFACE, EGL_FALSE);
 }
@@ -1033,7 +841,7 @@
     egl_surface_t const * const s = get_surface(surface);
     if (s->cnx->egl.eglBindTexImage) {
         return s->cnx->egl.eglBindTexImage(
-                dp->disp[s->impl].dpy, s->surface, buffer);
+                dp->disp.dpy, s->surface, buffer);
     }
     return setError(EGL_BAD_SURFACE, EGL_FALSE);
 }
@@ -1053,7 +861,7 @@
     egl_surface_t const * const s = get_surface(surface);
     if (s->cnx->egl.eglReleaseTexImage) {
         return s->cnx->egl.eglReleaseTexImage(
-                dp->disp[s->impl].dpy, s->surface, buffer);
+                dp->disp.dpy, s->surface, buffer);
     }
     return setError(EGL_BAD_SURFACE, EGL_FALSE);
 }
@@ -1066,17 +874,11 @@
     if (!dp) return EGL_FALSE;
 
     EGLBoolean res = EGL_TRUE;
-    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso) {
-            if (cnx->egl.eglSwapInterval) {
-                if (cnx->egl.eglSwapInterval(
-                        dp->disp[i].dpy, interval) == EGL_FALSE) {
-                    res = EGL_FALSE;
-                }
-            }
-        }
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglSwapInterval) {
+        res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
     }
+
     return res;
 }
 
@@ -1089,23 +891,15 @@
 {
     clearError();
 
-    // could be called before eglInitialize(), but we wouldn't have a context
-    // then, and this function would return GL_TRUE, which isn't wrong.
-    EGLBoolean res = EGL_TRUE;
-    EGLContext ctx = getContext();
-    if (ctx) {
-        egl_context_t const * const c = get_context(ctx);
-        if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        if (uint32_t(c->impl)>=2)
-            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        egl_connection_t* const cnx = &gEGLImpl[c->impl];
-        if (!cnx->dso) 
-            return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-        if (cnx->egl.eglWaitClient) {
-            res = cnx->egl.eglWaitClient();
-        } else {
-            res = cnx->egl.eglWaitGL();
-        }
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (!cnx->dso)
+        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+    EGLBoolean res;
+    if (cnx->egl.eglWaitClient) {
+        res = cnx->egl.eglWaitClient();
+    } else {
+        res = cnx->egl.eglWaitGL();
     }
     return res;
 }
@@ -1120,15 +914,9 @@
 
     // bind this API on all EGLs
     EGLBoolean res = EGL_TRUE;
-    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso) {
-            if (cnx->egl.eglBindAPI) {
-                if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
-                    res = EGL_FALSE;
-                }
-            }
-        }
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglBindAPI) {
+        res = cnx->egl.eglBindAPI(api);
     }
     return res;
 }
@@ -1141,16 +929,11 @@
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
     }
 
-    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso) {
-            if (cnx->egl.eglQueryAPI) {
-                // the first one we find is okay, because they all
-                // should be the same
-                return cnx->egl.eglQueryAPI();
-            }
-        }
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglQueryAPI) {
+        return cnx->egl.eglQueryAPI();
     }
+
     // or, it can only be OpenGL ES
     return EGL_OPENGL_ES_API;
 }
@@ -1160,16 +943,13 @@
     clearError();
 
     // If there is context bound to the thread, release it
-    loseCurrent(get_context(getContext()));
+    egl_display_t::loseCurrent(get_context(getContext()));
 
-    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso) {
-            if (cnx->egl.eglReleaseThread) {
-                cnx->egl.eglReleaseThread();
-            }
-        }
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglReleaseThread) {
+        cnx->egl.eglReleaseThread();
     }
+
     egl_tls_t::clearTLS();
 #if EGL_TRACE
     if (gEGLDebugLevel > 0)
@@ -1189,9 +969,7 @@
     if (!cnx) return EGL_FALSE;
     if (cnx->egl.eglCreatePbufferFromClientBuffer) {
         return cnx->egl.eglCreatePbufferFromClientBuffer(
-                dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
-                buftype, buffer,
-                dp->configs[intptr_t(config)].config, attrib_list);
+                dp->disp.dpy, buftype, buffer, config, attrib_list);
     }
     return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
 }
@@ -1215,7 +993,7 @@
     egl_surface_t const * const s = get_surface(surface);
     if (s->cnx->egl.eglLockSurfaceKHR) {
         return s->cnx->egl.eglLockSurfaceKHR(
-                dp->disp[s->impl].dpy, s->surface, attrib_list);
+                dp->disp.dpy, s->surface, attrib_list);
     }
     return setError(EGL_BAD_DISPLAY, EGL_FALSE);
 }
@@ -1233,8 +1011,7 @@
 
     egl_surface_t const * const s = get_surface(surface);
     if (s->cnx->egl.eglUnlockSurfaceKHR) {
-        return s->cnx->egl.eglUnlockSurfaceKHR(
-                dp->disp[s->impl].dpy, s->surface);
+        return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
     }
     return setError(EGL_BAD_DISPLAY, EGL_FALSE);
 }
@@ -1254,12 +1031,12 @@
         egl_context_t * const c = get_context(ctx);
         // since we have an EGLContext, we know which implementation to use
         EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
-                dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
+                dp->disp.dpy, c->context, target, buffer, attrib_list);
         if (image == EGL_NO_IMAGE_KHR)
             return image;
             
         egl_image_t* result = new egl_image_t(dpy, ctx);
-        result->images[c->impl] = image;
+        result->image = image;
         return (EGLImageKHR)result;
     } else {
         // EGL_NO_CONTEXT is a valid parameter
@@ -1271,23 +1048,14 @@
 
         EGLint currentError = eglGetError();
 
-        EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
-        bool success = false;
-        for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-            egl_connection_t* const cnx = &gEGLImpl[i];
-            implImages[i] = EGL_NO_IMAGE_KHR;
-            if (cnx->dso) {
-                if (cnx->egl.eglCreateImageKHR) {
-                    implImages[i] = cnx->egl.eglCreateImageKHR(
-                            dp->disp[i].dpy, ctx, target, buffer, attrib_list);
-                    if (implImages[i] != EGL_NO_IMAGE_KHR) {
-                        success = true;
-                    }
-                }
-            }
+        EGLImageKHR implImage = EGL_NO_IMAGE_KHR;
+        egl_connection_t* const cnx = &gEGLImpl;
+        if (cnx->dso && cnx->egl.eglCreateImageKHR) {
+            implImage = cnx->egl.eglCreateImageKHR(
+                    dp->disp.dpy, ctx, target, buffer, attrib_list);
         }
 
-        if (!success) {
+        if (implImage == EGL_NO_IMAGE_KHR) {
             // failure, if there was an error when we entered this function,
             // the error flag must not be updated.
             // Otherwise, the error is whatever happened in the implementation
@@ -1299,13 +1067,12 @@
         } else {
             // In case of success, we need to clear all error flags
             // (especially those caused by the implementation that didn't
-            // succeed). TODO: we could avoid this if we knew this was
-            // a "full" success (all implementation succeeded).
+            // succeed).
             eglGetError();
         }
 
         egl_image_t* result = new egl_image_t(dpy, ctx);
-        memcpy(result->images, implImages, sizeof(implImages));
+        result->image = implImage;
         return (EGLImageKHR)result;
     }
 }
@@ -1322,19 +1089,17 @@
 
     egl_image_t* image = get_image(img);
     bool success = false;
-    for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (image->images[i] != EGL_NO_IMAGE_KHR) {
-            if (cnx->dso) {
-                if (cnx->egl.eglDestroyImageKHR) {
-                    if (cnx->egl.eglDestroyImageKHR(
-                            dp->disp[i].dpy, image->images[i])) {
-                        success = true;
-                    }
-                }
+
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (image->image != EGL_NO_IMAGE_KHR) {
+        if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
+            if (cnx->egl.eglDestroyImageKHR(
+                    dp->disp.dpy, image->image)) {
+                success = true;
             }
         }
     }
+
     if (!success)
         return EGL_FALSE;
 
@@ -1364,7 +1129,7 @@
     EGLSyncKHR result = EGL_NO_SYNC_KHR;
     if (c->cnx->egl.eglCreateSyncKHR) {
         EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
-                dp->disp[c->impl].dpy, type, attrib_list);
+                dp->disp.dpy, type, attrib_list);
         if (sync == EGL_NO_SYNC_KHR)
             return sync;
         result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
@@ -1392,7 +1157,7 @@
     egl_context_t * const c = get_context(ctx);
     if (c->cnx->egl.eglDestroySyncKHR) {
         result = c->cnx->egl.eglDestroySyncKHR(
-                dp->disp[c->impl].dpy, syncObject->sync);
+                dp->disp.dpy, syncObject->sync);
         if (result)
             _s.terminate();
     }
@@ -1418,7 +1183,7 @@
     egl_context_t * const c = get_context(ctx);
     if (c->cnx->egl.eglClientWaitSyncKHR) {
         return c->cnx->egl.eglClientWaitSyncKHR(
-                dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
+                dp->disp.dpy, syncObject->sync, flags, timeout);
     }
 
     return EGL_FALSE;
@@ -1444,7 +1209,7 @@
     egl_context_t * const c = get_context(ctx);
     if (c->cnx->egl.eglGetSyncAttribKHR) {
         return c->cnx->egl.eglGetSyncAttribKHR(
-                dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
+                dp->disp.dpy, syncObject->sync, attribute, value);
     }
 
     return EGL_FALSE;
@@ -1468,12 +1233,10 @@
     }
 
     EGLuint64NV ret = 0;
-    egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
+    egl_connection_t* const cnx = &gEGLImpl;
 
-    if (cnx->dso) {
-        if (cnx->egl.eglGetSystemTimeFrequencyNV) {
-            return cnx->egl.eglGetSystemTimeFrequencyNV();
-        }
+    if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
+        return cnx->egl.eglGetSystemTimeFrequencyNV();
     }
 
     return setErrorQuiet(EGL_BAD_DISPLAY, 0);
@@ -1488,12 +1251,10 @@
     }
 
     EGLuint64NV ret = 0;
-    egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE];
+    egl_connection_t* const cnx = &gEGLImpl;
 
-    if (cnx->dso) {
-        if (cnx->egl.eglGetSystemTimeNV) {
-            return cnx->egl.eglGetSystemTimeNV();
-        }
+    if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
+        return cnx->egl.eglGetSystemTimeNV();
     }
 
     return setErrorQuiet(EGL_BAD_DISPLAY, 0);
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 7fd6519..c79fb5f 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -83,39 +83,39 @@
 
 void egl_cache_t::initialize(egl_display_t *display) {
     Mutex::Autolock lock(mMutex);
-    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
-            const char* exts = display->disp[i].queryString.extensions;
-            size_t bcExtLen = strlen(BC_EXT_STR);
-            size_t extsLen = strlen(exts);
-            bool equal = !strcmp(BC_EXT_STR, exts);
-            bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1);
-            bool atEnd = (bcExtLen+1) < extsLen &&
-                    !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1));
-            bool inMiddle = strstr(exts, " " BC_EXT_STR " ");
-            if (equal || atStart || atEnd || inMiddle) {
-                PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
-                eglSetBlobCacheFuncsANDROID =
-                        reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
+
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
+        const char* exts = display->disp.queryString.extensions;
+        size_t bcExtLen = strlen(BC_EXT_STR);
+        size_t extsLen = strlen(exts);
+        bool equal = !strcmp(BC_EXT_STR, exts);
+        bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1);
+        bool atEnd = (bcExtLen+1) < extsLen &&
+                !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1));
+        bool inMiddle = strstr(exts, " " BC_EXT_STR " ");
+        if (equal || atStart || atEnd || inMiddle) {
+            PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
+            eglSetBlobCacheFuncsANDROID =
+                    reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
                             cnx->egl.eglGetProcAddress(
                                     "eglSetBlobCacheFuncsANDROID"));
-                if (eglSetBlobCacheFuncsANDROID == NULL) {
-                    ALOGE("EGL_ANDROID_blob_cache advertised by display %d, "
-                            "but unable to get eglSetBlobCacheFuncsANDROID", i);
-                    continue;
-                }
+            if (eglSetBlobCacheFuncsANDROID == NULL) {
+                ALOGE("EGL_ANDROID_blob_cache advertised, "
+                        "but unable to get eglSetBlobCacheFuncsANDROID");
+                return;
+            }
 
-                eglSetBlobCacheFuncsANDROID(display->disp[i].dpy,
-                        android::setBlob, android::getBlob);
-                EGLint err = cnx->egl.eglGetError();
-                if (err != EGL_SUCCESS) {
-                    ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: "
-                            "%#x", err);
-                }
+            eglSetBlobCacheFuncsANDROID(display->disp.dpy,
+                    android::setBlob, android::getBlob);
+            EGLint err = cnx->egl.eglGetError();
+            if (err != EGL_SUCCESS) {
+                ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: "
+                        "%#x", err);
             }
         }
     }
+
     mInitialized = true;
 }
 
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 53eaf9a..c85b4ce 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -60,18 +60,12 @@
 extern void initEglTraceLevel();
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 
-static int cmp_configs(const void* a, const void *b) {
-    const egl_config_t& c0 = *(egl_config_t const *)a;
-    const egl_config_t& c1 = *(egl_config_t const *)b;
-    return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
-}
-
 // ----------------------------------------------------------------------------
 
 egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
 
 egl_display_t::egl_display_t() :
-    magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) {
+    magic('_dpy'), refs(0) {
 }
 
 egl_display_t::~egl_display_t() {
@@ -119,15 +113,13 @@
     // get our driver loader
     Loader& loader(Loader::getInstance());
 
-    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) {
-            EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
-            disp[i].dpy = dpy;
-            if (dpy == EGL_NO_DISPLAY) {
-                loader.close(cnx->dso);
-                cnx->dso = NULL;
-            }
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
+        EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
+        disp.dpy = dpy;
+        if (dpy == EGL_NO_DISPLAY) {
+            loader.close(cnx->dso);
+            cnx->dso = NULL;
         }
     }
 
@@ -160,12 +152,11 @@
     // initialize each EGL and
     // build our own extension string first, based on the extension we know
     // and the extension supported by our client implementation
-    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        cnx->major = -1;
-        cnx->minor = -1;
-        if (!cnx->dso)
-            continue;
+
+    egl_connection_t* const cnx = &gEGLImpl;
+    cnx->major = -1;
+    cnx->minor = -1;
+    if (cnx->dso) {
 
 #if defined(ADRENO130)
 #warning "Adreno-130 eglInitialize() workaround"
@@ -177,31 +168,30 @@
          * eglGetDisplay() before calling eglInitialize();
          */
         if (i == IMPL_HARDWARE) {
-            disp[i].dpy =
-            cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+            disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
         }
 #endif
 
-        EGLDisplay idpy = disp[i].dpy;
+        EGLDisplay idpy = disp.dpy;
         if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
-            //ALOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
-            //        i, idpy, cnx->major, cnx->minor, cnx);
+            //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p",
+            //        idpy, cnx->major, cnx->minor, cnx);
 
             // display is now initialized
-            disp[i].state = egl_display_t::INITIALIZED;
+            disp.state = egl_display_t::INITIALIZED;
 
             // get the query-strings for this display for each implementation
-            disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy,
+            disp.queryString.vendor = cnx->egl.eglQueryString(idpy,
                     EGL_VENDOR);
-            disp[i].queryString.version = cnx->egl.eglQueryString(idpy,
+            disp.queryString.version = cnx->egl.eglQueryString(idpy,
                     EGL_VERSION);
-            disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy,
+            disp.queryString.extensions = cnx->egl.eglQueryString(idpy,
                     EGL_EXTENSIONS);
-            disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy,
+            disp.queryString.clientApi = cnx->egl.eglQueryString(idpy,
                     EGL_CLIENT_APIS);
 
         } else {
-            ALOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
+            ALOGW("eglInitialize(%p) failed (%s)", idpy,
                     egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
         }
     }
@@ -211,7 +201,7 @@
     mVersionString.setTo(sVersionString);
     mClientApiString.setTo(sClientApiString);
 
-    // we only add extensions that exist in at least one implementation
+    // we only add extensions that exist in the implementation
     char const* start = sExtensionString;
     char const* end;
     do {
@@ -223,15 +213,13 @@
             if (len) {
                 // NOTE: we could avoid the copy if we had strnstr.
                 const String8 ext(start, len);
-                // now go through all implementations and look for this extension
-                for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
-                    if (disp[i].queryString.extensions) {
-                        // if we find it, add this extension string to our list
-                        // (and don't forget the space)
-                        const char* match = strstr(disp[i].queryString.extensions, ext.string());
-                        if (match && (match[len] == ' ' || match[len] == 0)) {
-                            mExtensionString.append(start, len+1);
-                        }
+                // now look for this extension
+                if (disp.queryString.extensions) {
+                    // if we find it, add this extension string to our list
+                    // (and don't forget the space)
+                    const char* match = strstr(disp.queryString.extensions, ext.string());
+                    if (match && (match[len] == ' ' || match[len] == 0)) {
+                        mExtensionString.append(start, len+1);
                     }
                 }
             }
@@ -242,52 +230,12 @@
 
     egl_cache_t::get()->initialize(this);
 
-    EGLBoolean res = EGL_FALSE;
-    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
-            EGLint n;
-            if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) {
-                disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n);
-                if (disp[i].config) {
-                    if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n,
-                            &disp[i].numConfigs)) {
-                        numTotalConfigs += n;
-                        res = EGL_TRUE;
-                    }
-                }
-            }
-        }
-    }
-
-    if (res == EGL_TRUE) {
-        configs = new egl_config_t[numTotalConfigs];
-        for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
-            egl_connection_t* const cnx = &gEGLImpl[i];
-            if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
-                for (int j = 0; j < disp[i].numConfigs; j++) {
-                    configs[k].impl = i;
-                    configs[k].config = disp[i].config[j];
-                    configs[k].configId = k + 1; // CONFIG_ID start at 1
-                    // store the implementation's CONFIG_ID
-                    cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j],
-                            EGL_CONFIG_ID, &configs[k].implConfigId);
-                    k++;
-                }
-            }
-        }
-
-        // sort our configurations so we can do binary-searches
-        qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs);
-
-        refs++;
-        if (major != NULL)
-            *major = VERSION_MAJOR;
-        if (minor != NULL)
-            *minor = VERSION_MINOR;
-        return EGL_TRUE;
-    }
-    return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+    refs++;
+    if (major != NULL)
+        *major = VERSION_MAJOR;
+    if (minor != NULL)
+        *minor = VERSION_MINOR;
+    return EGL_TRUE;
 }
 
 EGLBoolean egl_display_t::terminate() {
@@ -305,22 +253,15 @@
     }
 
     EGLBoolean res = EGL_FALSE;
-    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
-        egl_connection_t* const cnx = &gEGLImpl[i];
-        if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) {
-            if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) {
-                ALOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy,
-                        egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
-            }
-            // REVISIT: it's unclear what to do if eglTerminate() fails
-            free(disp[i].config);
-
-            disp[i].numConfigs = 0;
-            disp[i].config = 0;
-            disp[i].state = egl_display_t::TERMINATED;
-
-            res = EGL_TRUE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
+        if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
+            ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
+                    egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
         }
+        // REVISIT: it's unclear what to do if eglTerminate() fails
+        disp.state = egl_display_t::TERMINATED;
+        res = EGL_TRUE;
     }
 
     // Mark all objects remaining in the list as terminated, unless
@@ -337,11 +278,81 @@
     objects.clear();
 
     refs--;
-    numTotalConfigs = 0;
-    delete[] configs;
     return res;
 }
 
+void egl_display_t::loseCurrent(egl_context_t * cur_c)
+{
+    if (cur_c) {
+        egl_display_t* display = cur_c->getDisplay();
+        if (display) {
+            display->loseCurrentImpl(cur_c);
+        }
+    }
+}
+
+void egl_display_t::loseCurrentImpl(egl_context_t * cur_c)
+{
+    // by construction, these are either 0 or valid (possibly terminated)
+    // it should be impossible for these to be invalid
+    ContextRef _cur_c(cur_c);
+    SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
+    SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
+
+    { // scope for the lock
+        Mutex::Autolock _l(lock);
+        cur_c->onLooseCurrent();
+
+    }
+
+    // This cannot be called with the lock held because it might end-up
+    // calling back into EGL (in particular when a surface is destroyed
+    // it calls ANativeWindow::disconnect
+    _cur_c.release();
+    _cur_r.release();
+    _cur_d.release();
+}
+
+EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
+        EGLSurface draw, EGLSurface read, EGLContext ctx,
+        EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
+{
+    EGLBoolean result;
+
+    // by construction, these are either 0 or valid (possibly terminated)
+    // it should be impossible for these to be invalid
+    ContextRef _cur_c(cur_c);
+    SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
+    SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
+
+    { // scope for the lock
+        Mutex::Autolock _l(lock);
+        if (c) {
+            result = c->cnx->egl.eglMakeCurrent(
+                    disp.dpy, impl_draw, impl_read, impl_ctx);
+            if (result == EGL_TRUE) {
+                c->onMakeCurrent(draw, read);
+            }
+        } else {
+            result = cur_c->cnx->egl.eglMakeCurrent(
+                    disp.dpy, impl_draw, impl_read, impl_ctx);
+            if (result == EGL_TRUE) {
+                cur_c->onLooseCurrent();
+            }
+        }
+    }
+
+    if (result == EGL_TRUE) {
+        // This cannot be called with the lock held because it might end-up
+        // calling back into EGL (in particular when a surface is destroyed
+        // it calls ANativeWindow::disconnect
+        _cur_c.release();
+        _cur_r.release();
+        _cur_d.release();
+    }
+
+    return result;
+}
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 042ae07..6348228 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -39,30 +39,15 @@
 // ----------------------------------------------------------------------------
 
 class egl_object_t;
+class egl_context_t;
 class egl_connection_t;
 
 // ----------------------------------------------------------------------------
 
-struct egl_config_t {
-    egl_config_t() {}
-    egl_config_t(int impl, EGLConfig config)
-        : impl(impl), config(config), configId(0), implConfigId(0) { }
-    int         impl;           // the implementation this config is for
-    EGLConfig   config;         // the implementation's EGLConfig
-    EGLint      configId;       // our CONFIG_ID
-    EGLint      implConfigId;   // the implementation's CONFIG_ID
-    inline bool operator < (const egl_config_t& rhs) const {
-        if (impl < rhs.impl) return true;
-        if (impl > rhs.impl) return false;
-        return config < rhs.config;
-    }
-};
-
-// ----------------------------------------------------------------------------
-
 class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
     static egl_display_t sDisplay[NUM_DISPLAYS];
     EGLDisplay getDisplay(EGLNativeDisplayType display);
+    void loseCurrentImpl(egl_context_t * cur_c);
 
 public:
     enum {
@@ -84,10 +69,14 @@
     // add reference to this object. returns true if this is a valid object.
     bool getObject(egl_object_t* object) const;
 
-
     static egl_display_t* get(EGLDisplay dpy);
     static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
 
+    EGLBoolean makeCurrent(egl_context_t* c, egl_context_t* cur_c,
+            EGLSurface draw, EGLSurface read, EGLContext ctx,
+            EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx);
+    static void loseCurrent(egl_context_t * cur_c);
+
     inline bool isReady() const { return (refs > 0); }
     inline bool isValid() const { return magic == '_dpy'; }
     inline bool isAlive() const { return isValid(); }
@@ -107,12 +96,9 @@
     };
 
     struct DisplayImpl {
-        DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
-                        state(NOT_INITIALIZED), numConfigs(0) { }
+        DisplayImpl() : dpy(EGL_NO_DISPLAY), state(NOT_INITIALIZED) { }
         EGLDisplay  dpy;
-        EGLConfig*  config;
         EGLint      state;
-        EGLint      numConfigs;
         strings_t   queryString;
     };
 
@@ -120,9 +106,7 @@
     uint32_t        magic;
 
 public:
-    DisplayImpl     disp[IMPL_NUM_IMPLEMENTATIONS];
-    EGLint          numTotalConfigs;
-    egl_config_t*   configs;
+    DisplayImpl     disp;
 
 private:
             uint32_t                    refs;
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 26e8c3e..d0cbb31 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -62,5 +62,41 @@
 }
 
 // ----------------------------------------------------------------------------
+
+egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
+        egl_connection_t const* cnx, int version) :
+    egl_object_t(get_display(dpy)), dpy(dpy), context(context),
+            config(config), read(0), draw(0), cnx(cnx),
+            version(version)
+{
+}
+
+void egl_context_t::onLooseCurrent() {
+    read = NULL;
+    draw = NULL;
+}
+
+void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) {
+    this->read = read;
+    this->draw = draw;
+
+    /*
+     * Here we cache the GL_EXTENSIONS string for this context and we
+     * add the extensions always handled by the wrapper
+     */
+
+    if (gl_extensions.isEmpty()) {
+        // call the implementation's glGetString(GL_EXTENSIONS)
+        const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
+        gl_extensions.setTo(exts);
+        if (gl_extensions.find("GL_EXT_debug_marker") < 0) {
+            String8 temp("GL_EXT_debug_marker ");
+            temp.append(gl_extensions);
+            gl_extensions.setTo(temp);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 7106fa5..f137bad 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -28,6 +28,7 @@
 #include <GLES/glext.h>
 
 #include <utils/threads.h>
+#include <utils/String8.h>
 
 #include <system/window.h>
 
@@ -124,7 +125,7 @@
 
 // ----------------------------------------------------------------------------
 
-class egl_surface_t: public egl_object_t {
+class egl_surface_t : public egl_object_t {
 protected:
     ~egl_surface_t() {
         ANativeWindow* const window = win.get();
@@ -139,15 +140,14 @@
     typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
 
     egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
-            EGLSurface surface, int impl, egl_connection_t const* cnx) :
+            EGLSurface surface, egl_connection_t const* cnx) :
         egl_object_t(get_display(dpy)), dpy(dpy), surface(surface),
-                config(config), win(win), impl(impl), cnx(cnx) {
+                config(config), win(win), cnx(cnx) {
     }
     EGLDisplay dpy;
     EGLSurface surface;
     EGLConfig config;
     sp<ANativeWindow> win;
-    int impl;
     egl_connection_t const* cnx;
 };
 
@@ -158,19 +158,19 @@
     typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
 
     egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
-            int impl, egl_connection_t const* cnx, int version) :
-        egl_object_t(get_display(dpy)), dpy(dpy), context(context),
-                config(config), read(0), draw(0), impl(impl), cnx(cnx),
-                version(version) {
-    }
+            egl_connection_t const* cnx, int version);
+
+    void onLooseCurrent();
+    void onMakeCurrent(EGLSurface draw, EGLSurface read);
+
     EGLDisplay dpy;
     EGLContext context;
     EGLConfig config;
     EGLSurface read;
     EGLSurface draw;
-    int impl;
     egl_connection_t const* cnx;
     int version;
+    String8 gl_extensions;
 };
 
 class egl_image_t: public egl_object_t {
@@ -180,12 +180,11 @@
     typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
 
     egl_image_t(EGLDisplay dpy, EGLContext context) :
-        egl_object_t(get_display(dpy)), dpy(dpy), context(context) {
-        memset(images, 0, sizeof(images));
-    }
+        egl_object_t(get_display(dpy)),
+        dpy(dpy), context(context), image(EGL_NO_IMAGE_KHR) { }
     EGLDisplay dpy;
     EGLContext context;
-    EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
+    EGLImageKHR image;
 };
 
 class egl_sync_t: public egl_object_t {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 107acd9..c900c1c 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -19,31 +19,24 @@
 
 #include "hooks.h"
 
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
 
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 4
-
 //  EGLDisplay are global, not attached to a given thread
 const unsigned int NUM_DISPLAYS = 1;
 
-enum {
-    IMPL_HARDWARE = 0,
-    IMPL_SOFTWARE,
-    IMPL_NUM_IMPLEMENTATIONS
-};
-
-enum {
-    GLESv1_INDEX = 0,
-    GLESv2_INDEX = 1,
-};
-
 // ----------------------------------------------------------------------------
 
-struct egl_connection_t
-{
+struct egl_connection_t {
+    enum {
+        GLESv1_INDEX = 0,
+        GLESv2_INDEX = 1
+    };
+
     inline egl_connection_t() : dso(0) { }
     void *              dso;
     gl_hooks_t *        hooks[2];
@@ -54,15 +47,16 @@
 
 // ----------------------------------------------------------------------------
 
-extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+extern gl_hooks_t gHooks[2];
 extern gl_hooks_t gHooksNoContext;
 extern pthread_key_t gGLWrapperKey;
 extern "C" void gl_unimplemented();
+extern "C" void gl_noop();
 
 extern char const * const gl_names[];
 extern char const * const egl_names[];
 
-extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
+extern egl_connection_t gEGLImpl;
 
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index f89c865..8dcf38d 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -82,23 +82,41 @@
 
 #endif
 
+
 #define GL_EXTENSION_LIST(name) \
-        name(0)   name(1)   name(2)   name(3)   \
-        name(4)   name(5)   name(6)   name(7)   \
-        name(8)   name(9)   name(10)  name(11)  \
-        name(12)  name(13)  name(14)  name(15)  \
-        name(16)  name(17)  name(18)  name(19)  \
-        name(20)  name(21)  name(22)  name(23)  \
-        name(24)  name(25)  name(26)  name(27)  \
-        name(28)  name(29)  name(30)  name(31)  \
-        name(32)  name(33)  name(34)  name(35)  \
-        name(36)  name(37)  name(38)  name(39)  \
-        name(40)  name(41)  name(42)  name(43)  \
-        name(44)  name(45)  name(46)  name(47)  \
-        name(48)  name(49)  name(50)  name(51)  \
-        name(52)  name(53)  name(54)  name(55)  \
-        name(56)  name(57)  name(58)  name(59)  \
-        name(60)  name(61)  name(62)  name(63)
+    name(0)   name(1)   name(2)   name(3)   name(4)   name(5)   name(6)   name(7)  \
+    name(8)   name(9)   name(10)  name(11)  name(12)  name(13)  name(14)  name(15) \
+    name(16)  name(17)  name(18)  name(19)  name(20)  name(21)  name(22)  name(23) \
+    name(24)  name(25)  name(26)  name(27)  name(28)  name(29)  name(30)  name(31) \
+    name(32)  name(33)  name(34)  name(35)  name(36)  name(37)  name(38)  name(39) \
+    name(40)  name(41)  name(42)  name(43)  name(44)  name(45)  name(46)  name(47) \
+    name(48)  name(49)  name(50)  name(51)  name(52)  name(53)  name(54)  name(55) \
+    name(56)  name(57)  name(58)  name(59)  name(60)  name(61)  name(62)  name(63) \
+    name(64)  name(65)  name(66)  name(67)  name(68)  name(69)  name(70)  name(71) \
+    name(72)  name(73)  name(74)  name(75)  name(76)  name(77)  name(78)  name(79) \
+    name(80)  name(81)  name(82)  name(83)  name(84)  name(85)  name(86)  name(87) \
+    name(88)  name(89)  name(90)  name(91)  name(92)  name(93)  name(94)  name(95) \
+    name(96)  name(97)  name(98)  name(99)  \
+    name(100) name(101) name(102) name(103) name(104) name(105) name(106) name(107) \
+    name(108) name(109) name(110) name(111) name(112) name(113) name(114) name(115) \
+    name(116) name(117) name(118) name(119) name(120) name(121) name(122) name(123) \
+    name(124) name(125) name(126) name(127) name(128) name(129) name(130) name(131) \
+    name(132) name(133) name(134) name(135) name(136) name(137) name(138) name(139) \
+    name(140) name(141) name(142) name(143) name(144) name(145) name(146) name(147) \
+    name(148) name(149) name(150) name(151) name(152) name(153) name(154) name(155) \
+    name(156) name(157) name(158) name(159) name(160) name(161) name(162) name(163) \
+    name(164) name(165) name(166) name(167) name(168) name(169) name(170) name(171) \
+    name(172) name(173) name(174) name(175) name(176) name(177) name(178) name(179) \
+    name(180) name(181) name(182) name(183) name(184) name(185) name(186) name(187) \
+    name(188) name(189) name(190) name(191) name(192) name(193) name(194) name(195) \
+    name(196) name(197) name(198) name(199) \
+    name(200) name(201) name(202) name(203) name(204) name(205) name(206) name(207) \
+    name(208) name(209) name(210) name(211) name(212) name(213) name(214) name(215) \
+    name(216) name(217) name(218) name(219) name(220) name(221) name(222) name(223) \
+    name(224) name(225) name(226) name(227) name(228) name(229) name(230) name(231) \
+    name(232) name(233) name(234) name(235) name(236) name(237) name(238) name(239) \
+    name(240) name(241) name(242) name(243) name(244) name(245) name(246) name(247) \
+    name(248) name(249) name(250) name(251) name(252) name(253) name(254) name(255)
 
 
 GL_EXTENSION_LIST( GL_EXTENSION )
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index df22b96..79aa3cd 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -110,6 +110,20 @@
 #undef CALL_GL_API
 #undef CALL_GL_API_RETURN
 
+/*
+ * glGetString() is special because we expose some extensions in the wrapper
+ */
+
+extern "C" const GLubyte * __glGetString(GLenum name);
+
+const GLubyte * glGetString(GLenum name)
+{
+    const GLubyte * ret = egl_get_string_for_current_context(name);
+    if (ret == NULL) {
+        ret = __glGetString(name);
+    }
+    return ret;
+}
 
 /*
  * These GL calls are special because they need to EGL to retrieve some
diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in
index 5164450..9a89a52 100644
--- a/opengl/libs/GLES2/gl2_api.in
+++ b/opengl/libs/GLES2/gl2_api.in
@@ -211,7 +211,7 @@
 void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) {
     CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
 }
-const GLubyte* API_ENTRY(glGetString)(GLenum name) {
+const GLubyte* API_ENTRY(__glGetString)(GLenum name) {
     CALL_GL_API_RETURN(glGetString, name);
 }
 void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) {
diff --git a/opengl/libs/GLES2/gl2ext_api.in b/opengl/libs/GLES2/gl2ext_api.in
index e965625..a8907fd 100644
--- a/opengl/libs/GLES2/gl2ext_api.in
+++ b/opengl/libs/GLES2/gl2ext_api.in
@@ -82,21 +82,204 @@
 void API_ENTRY(glGetPerfMonitorCounterDataAMD)(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) {
     CALL_GL_API(glGetPerfMonitorCounterDataAMD, monitor, pname, dataSize, data, bytesWritten);
 }
+void API_ENTRY(glBlitFramebufferANGLE)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+    CALL_GL_API(glBlitFramebufferANGLE, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+void API_ENTRY(glRenderbufferStorageMultisampleANGLE)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glRenderbufferStorageMultisampleANGLE, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glRenderbufferStorageMultisampleAPPLE)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glRenderbufferStorageMultisampleAPPLE, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glResolveMultisampleFramebufferAPPLE)(void) {
+    CALL_GL_API(glResolveMultisampleFramebufferAPPLE);
+}
+void API_ENTRY(glLabelObjectEXT)(GLenum type, GLuint object, GLsizei length, const GLchar *label) {
+    CALL_GL_API(glLabelObjectEXT, type, object, length, label);
+}
+void API_ENTRY(glGetObjectLabelEXT)(GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label) {
+    CALL_GL_API(glGetObjectLabelEXT, type, object, bufSize, length, label);
+}
+void API_ENTRY(glInsertEventMarkerEXT)(GLsizei length, const GLchar *marker) {
+    CALL_GL_API(glInsertEventMarkerEXT, length, marker);
+}
+void API_ENTRY(glPushGroupMarkerEXT)(GLsizei length, const GLchar *marker) {
+    CALL_GL_API(glPushGroupMarkerEXT, length, marker);
+}
+void API_ENTRY(glPopGroupMarkerEXT)(void) {
+    CALL_GL_API(glPopGroupMarkerEXT);
+}
 void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) {
     CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments);
 }
+void API_ENTRY(glRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glRenderbufferStorageMultisampleEXT, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glFramebufferTexture2DMultisampleEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) {
+    CALL_GL_API(glFramebufferTexture2DMultisampleEXT, target, attachment, textarget, texture, level, samples);
+}
 void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) {
     CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount);
 }
 void API_ENTRY(glMultiDrawElementsEXT)(GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) {
     CALL_GL_API(glMultiDrawElementsEXT, mode, count, type, indices, primcount);
 }
+void API_ENTRY(glGenQueriesEXT)(GLsizei n, GLuint *ids) {
+    CALL_GL_API(glGenQueriesEXT, n, ids);
+}
+void API_ENTRY(glDeleteQueriesEXT)(GLsizei n, const GLuint *ids) {
+    CALL_GL_API(glDeleteQueriesEXT, n, ids);
+}
+GLboolean API_ENTRY(glIsQueryEXT)(GLuint id) {
+    CALL_GL_API_RETURN(glIsQueryEXT, id);
+}
+void API_ENTRY(glBeginQueryEXT)(GLenum target, GLuint id) {
+    CALL_GL_API(glBeginQueryEXT, target, id);
+}
+void API_ENTRY(glEndQueryEXT)(GLenum target) {
+    CALL_GL_API(glEndQueryEXT, target);
+}
+void API_ENTRY(glGetQueryivEXT)(GLenum target, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetQueryivEXT, target, pname, params);
+}
+void API_ENTRY(glGetQueryObjectuivEXT)(GLuint id, GLenum pname, GLuint *params) {
+    CALL_GL_API(glGetQueryObjectuivEXT, id, pname, params);
+}
+GLenum API_ENTRY(glGetGraphicsResetStatusEXT)(void) {
+    CALL_GL_API_RETURN(glGetGraphicsResetStatusEXT);
+}
+void API_ENTRY(glReadnPixelsEXT)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) {
+    CALL_GL_API(glReadnPixelsEXT, x, y, width, height, format, type, bufSize, data);
+}
+void API_ENTRY(glGetnUniformfvEXT)(GLuint program, GLint location, GLsizei bufSize, float *params) {
+    CALL_GL_API(glGetnUniformfvEXT, program, location, bufSize, params);
+}
+void API_ENTRY(glGetnUniformivEXT)(GLuint program, GLint location, GLsizei bufSize, GLint *params) {
+    CALL_GL_API(glGetnUniformivEXT, program, location, bufSize, params);
+}
+void API_ENTRY(glUseProgramStagesEXT)(GLuint pipeline, GLbitfield stages, GLuint program) {
+    CALL_GL_API(glUseProgramStagesEXT, pipeline, stages, program);
+}
+void API_ENTRY(glActiveShaderProgramEXT)(GLuint pipeline, GLuint program) {
+    CALL_GL_API(glActiveShaderProgramEXT, pipeline, program);
+}
+GLuint API_ENTRY(glCreateShaderProgramvEXT)(GLenum type, GLsizei count, const GLchar **strings) {
+    CALL_GL_API_RETURN(glCreateShaderProgramvEXT, type, count, strings);
+}
+void API_ENTRY(glBindProgramPipelineEXT)(GLuint pipeline) {
+    CALL_GL_API(glBindProgramPipelineEXT, pipeline);
+}
+void API_ENTRY(glDeleteProgramPipelinesEXT)(GLsizei n, const GLuint *pipelines) {
+    CALL_GL_API(glDeleteProgramPipelinesEXT, n, pipelines);
+}
+void API_ENTRY(glGenProgramPipelinesEXT)(GLsizei n, GLuint *pipelines) {
+    CALL_GL_API(glGenProgramPipelinesEXT, n, pipelines);
+}
+GLboolean API_ENTRY(glIsProgramPipelineEXT)(GLuint pipeline) {
+    CALL_GL_API_RETURN(glIsProgramPipelineEXT, pipeline);
+}
+void API_ENTRY(glProgramParameteriEXT)(GLuint program, GLenum pname, GLint value) {
+    CALL_GL_API(glProgramParameteriEXT, program, pname, value);
+}
+void API_ENTRY(glGetProgramPipelineivEXT)(GLuint pipeline, GLenum pname, GLint *params) {
+    CALL_GL_API(glGetProgramPipelineivEXT, pipeline, pname, params);
+}
+void API_ENTRY(glProgramUniform1iEXT)(GLuint program, GLint location, GLint x) {
+    CALL_GL_API(glProgramUniform1iEXT, program, location, x);
+}
+void API_ENTRY(glProgramUniform2iEXT)(GLuint program, GLint location, GLint x, GLint y) {
+    CALL_GL_API(glProgramUniform2iEXT, program, location, x, y);
+}
+void API_ENTRY(glProgramUniform3iEXT)(GLuint program, GLint location, GLint x, GLint y, GLint z) {
+    CALL_GL_API(glProgramUniform3iEXT, program, location, x, y, z);
+}
+void API_ENTRY(glProgramUniform4iEXT)(GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w) {
+    CALL_GL_API(glProgramUniform4iEXT, program, location, x, y, z, w);
+}
+void API_ENTRY(glProgramUniform1fEXT)(GLuint program, GLint location, GLfloat x) {
+    CALL_GL_API(glProgramUniform1fEXT, program, location, x);
+}
+void API_ENTRY(glProgramUniform2fEXT)(GLuint program, GLint location, GLfloat x, GLfloat y) {
+    CALL_GL_API(glProgramUniform2fEXT, program, location, x, y);
+}
+void API_ENTRY(glProgramUniform3fEXT)(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z) {
+    CALL_GL_API(glProgramUniform3fEXT, program, location, x, y, z);
+}
+void API_ENTRY(glProgramUniform4fEXT)(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+    CALL_GL_API(glProgramUniform4fEXT, program, location, x, y, z, w);
+}
+void API_ENTRY(glProgramUniform1ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) {
+    CALL_GL_API(glProgramUniform1ivEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform2ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) {
+    CALL_GL_API(glProgramUniform2ivEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform3ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) {
+    CALL_GL_API(glProgramUniform3ivEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform4ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) {
+    CALL_GL_API(glProgramUniform4ivEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform1fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+    CALL_GL_API(glProgramUniform1fvEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform2fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+    CALL_GL_API(glProgramUniform2fvEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform3fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+    CALL_GL_API(glProgramUniform3fvEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform4fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+    CALL_GL_API(glProgramUniform4fvEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniformMatrix2fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    CALL_GL_API(glProgramUniformMatrix2fvEXT, program, location, count, transpose, value);
+}
+void API_ENTRY(glProgramUniformMatrix3fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    CALL_GL_API(glProgramUniformMatrix3fvEXT, program, location, count, transpose, value);
+}
+void API_ENTRY(glProgramUniformMatrix4fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    CALL_GL_API(glProgramUniformMatrix4fvEXT, program, location, count, transpose, value);
+}
+void API_ENTRY(glValidateProgramPipelineEXT)(GLuint pipeline) {
+    CALL_GL_API(glValidateProgramPipelineEXT, pipeline);
+}
+void API_ENTRY(glGetProgramPipelineInfoLogEXT)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    CALL_GL_API(glGetProgramPipelineInfoLogEXT, pipeline, bufSize, length, infoLog);
+}
+void API_ENTRY(glTexStorage1DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+    CALL_GL_API(glTexStorage1DEXT, target, levels, internalformat, width);
+}
+void API_ENTRY(glTexStorage2DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glTexStorage2DEXT, target, levels, internalformat, width, height);
+}
+void API_ENTRY(glTexStorage3DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+    CALL_GL_API(glTexStorage3DEXT, target, levels, internalformat, width, height, depth);
+}
+void API_ENTRY(glTextureStorage1DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+    CALL_GL_API(glTextureStorage1DEXT, texture, target, levels, internalformat, width);
+}
+void API_ENTRY(glTextureStorage2DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glTextureStorage2DEXT, texture, target, levels, internalformat, width, height);
+}
+void API_ENTRY(glTextureStorage3DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+    CALL_GL_API(glTextureStorage3DEXT, texture, target, levels, internalformat, width, height, depth);
+}
 void API_ENTRY(glRenderbufferStorageMultisampleIMG)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
     CALL_GL_API(glRenderbufferStorageMultisampleIMG, target, samples, internalformat, width, height);
 }
 void API_ENTRY(glFramebufferTexture2DMultisampleIMG)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) {
     CALL_GL_API(glFramebufferTexture2DMultisampleIMG, target, attachment, textarget, texture, level, samples);
 }
+void API_ENTRY(glCoverageMaskNV)(GLboolean mask) {
+    CALL_GL_API(glCoverageMaskNV, mask);
+}
+void API_ENTRY(glCoverageOperationNV)(GLenum operation) {
+    CALL_GL_API(glCoverageOperationNV, operation);
+}
+void API_ENTRY(glDrawBuffersNV)(GLsizei n, const GLenum *bufs) {
+    CALL_GL_API(glDrawBuffersNV, n, bufs);
+}
 void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) {
     CALL_GL_API(glDeleteFencesNV, n, fences);
 }
@@ -118,11 +301,11 @@
 void API_ENTRY(glSetFenceNV)(GLuint fence, GLenum condition) {
     CALL_GL_API(glSetFenceNV, fence, condition);
 }
-void API_ENTRY(glCoverageMaskNV)(GLboolean mask) {
-    CALL_GL_API(glCoverageMaskNV, mask);
+void API_ENTRY(glReadBufferNV)(GLenum mode) {
+    CALL_GL_API(glReadBufferNV, mode);
 }
-void API_ENTRY(glCoverageOperationNV)(GLenum operation) {
-    CALL_GL_API(glCoverageOperationNV, operation);
+void API_ENTRY(glAlphaFuncQCOM)(GLenum func, GLclampf ref) {
+    CALL_GL_API(glAlphaFuncQCOM, func, ref);
 }
 void API_ENTRY(glGetDriverControlsQCOM)(GLint *num, GLsizei size, GLuint *driverControls) {
     CALL_GL_API(glGetDriverControlsQCOM, num, size, driverControls);
diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py
deleted file mode 100755
index 96cde57..0000000
--- a/opengl/libs/GLES2_dbg/generate_api_cpp.py
+++ /dev/null
@@ -1,219 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-#
-# Copyright 2011, The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-import os
-import sys
-
-def RemoveAnnotation(line):
-    if line.find(":") >= 0:
-        annotation = line[line.find(":"): line.find(" ", line.find(":"))]
-        return line.replace(annotation, "*")
-    else:
-        return line
-
-def generate_api(lines):
-    externs = []
-    i = 0
-    # these have been hand written
-    skipFunctions = ["glDrawArrays", "glDrawElements"]
-
-    # these have an EXTEND_Debug_* macro for getting data
-    extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glReadPixels",
-"glShaderSource", "glTexImage2D", "glTexSubImage2D"]
-
-    # these also needs to be forwarded to DbgContext
-    contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",
-"glVertexAttribPointer", "glBindBuffer", "glBufferData", "glBufferSubData", "glDeleteBuffers",]
-
-    for line in lines:
-        if line.find("API_ENTRY(") >= 0: # a function prototype
-            returnType = line[0: line.find(" API_ENTRY(")]
-            functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
-            parameterList = line[line.find(")(") + 2: line.find(") {")]
-
-            #if line.find("*") >= 0:
-            #    extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)
-            #    externs.append(extern)
-            #    continue
-
-            if functionName in skipFunctions:
-                sys.stderr.write("!\n! skipping function '%s'\n!\n" % (functionName))
-                continue
-
-            parameters = parameterList.split(',')
-            paramIndex = 0
-            if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer
-                if not functionName in extendFunctions:
-                    # add function to list of functions that should be hand written, but generate code anyways
-                    extern = "%s Debug_%s(%s);" % (returnType, functionName, RemoveAnnotation(parameterList))
-                    sys.stderr.write("%s should be hand written\n" % (extern))
-                    print "// FIXME: this function has pointers, it should be hand written"
-                    externs.append(extern)
-
-            print "%s Debug_%s(%s)\n{" % (returnType, functionName, RemoveAnnotation(parameterList))
-            print "    glesv2debugger::Message msg;"
-
-            if parameterList == "void":
-                parameters = []
-            arguments = ""
-            paramNames = []
-            inout = ""
-            getData = ""
-
-            callerMembers = ""
-            setCallerMembers = ""
-            setMsgParameters = ""
-
-            for parameter in parameters:
-                const = parameter.find("const")
-                parameter = parameter.replace("const", "")
-                parameter = parameter.strip()
-                paramType = parameter.split(' ')[0]
-                paramName = parameter.split(' ')[1]
-                annotation = ""
-                arguments += paramName
-                if parameter.find(":") >= 0: # has annotation
-                    assert inout == "" # only one parameter should be annotated
-                    sys.stderr.write("%s is annotated: %s \n" % (functionName, paramType))
-                    inout = paramType.split(":")[2]
-                    annotation = paramType.split(":")[1]
-                    paramType = paramType.split(":")[0]
-                    count = 1
-                    countArg = ""
-                    if annotation.find("*") >= 0: # [1,n] * param
-                        count = int(annotation.split("*")[0])
-                        countArg = annotation.split("*")[1]
-                        assert countArg in paramNames
-                    elif annotation in paramNames:
-                        count = 1
-                        countArg = annotation
-                    elif annotation == "GLstring":
-                        annotation = "strlen(%s)" % (paramName)
-                    else:
-                        count = int(annotation)
-
-                    setMsgParameters += "    msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
-                    if paramType.find("void") >= 0:
-                        getData += "    msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(char));" % (paramName, annotation)
-                    else:
-                        getData += "    msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(%s));" % (paramName, annotation, paramType)
-                    paramType += "*"
-                else:
-                    if paramType == "GLfloat" or paramType == "GLclampf" or paramType.find("*") >= 0:
-                        setMsgParameters += "    msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
-                    else:
-                        setMsgParameters += "    msg.set_arg%d(%s);\n" % (paramIndex, paramName)
-                if paramIndex < len(parameters) - 1:
-                        arguments += ', '
-                if const >= 0:
-                    paramType = "const " + paramType
-                paramNames.append(paramName)
-                paramIndex += 1
-                callerMembers += "        %s %s;\n" % (paramType, paramName)
-                setCallerMembers += "    caller.%s = %s;\n" % (paramName, paramName)
-
-            print "    struct : public FunctionCall {"
-            print callerMembers
-            print "        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {"
-            if inout in ["out", "inout"]: # get timing excluding output data copy
-                print "            nsecs_t c0 = systemTime(timeMode);"
-            if returnType == "void":
-                print "            _c->%s(%s);" % (functionName, arguments)
-            else:
-                print "            const int * ret = reinterpret_cast<const int *>(_c->%s(%s));" % (functionName, arguments)
-                print "            msg.set_ret(ToInt(ret));"
-            if inout in ["out", "inout"]:
-                print "            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);"
-                print "        " + getData
-            if functionName in extendFunctions:
-                print "\
-#ifdef EXTEND_AFTER_CALL_Debug_%s\n\
-            EXTEND_AFTER_CALL_Debug_%s;\n\
-#endif" % (functionName, functionName)
-            if functionName in contextFunctions:
-                print "            getDbgContextThreadSpecific()->%s(%s);" % (functionName, arguments)
-            if returnType == "void":
-                print "            return 0;"
-            else:
-                print "            return ret;"
-            print """        }
-    } caller;"""
-            print setCallerMembers
-            print setMsgParameters
-
-            if line.find("*") >= 0 or line.find(":") >= 0:
-                print "    // FIXME: check for pointer usage"
-            if inout in ["in", "inout"]:
-                print getData
-            if functionName in extendFunctions:
-                print "\
-#ifdef EXTEND_Debug_%s\n\
-    EXTEND_Debug_%s;\n\
-#endif" % (functionName, functionName)
-            print "    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_%s);"\
-                % (functionName)
-            if returnType != "void":
-                if returnType == "GLboolean":
-                    print "    return static_cast<GLboolean>(reinterpret_cast<int>(ret));"
-                else:
-                    print "    return reinterpret_cast<%s>(ret);" % (returnType)
-            print "}\n"
-
-
-    print "// FIXME: the following functions should be written by hand"
-    for extern in externs:
-        print extern
-
-if __name__ == "__main__":
-    print """\
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-// auto generated by generate_api_cpp.py
-
-#include <utils/Debug.h>
-
-#include "src/header.h"
-#include "src/api.h"
-
-template<typename T> static int ToInt(const T & t)
-{
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
-    return (int &)t;
-}
-"""
-    lines = open("gl2_api_annotated.in").readlines()
-    generate_api(lines)
-    #lines = open("gl2ext_api.in").readlines()
-    #generate_api(lines)
-
-
diff --git a/opengl/libs/GLES2_dbg/generate_caller_cpp.py b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
deleted file mode 100755
index ee4208d..0000000
--- a/opengl/libs/GLES2_dbg/generate_caller_cpp.py
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-#
-# Copyright 2011, The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-import os
-import sys
-
-externs = []
-    
-def generate_caller(lines):
-    i = 0
-    output = ""
-    skipFunctions = []
-    
-    for line in lines:
-        if line.find("API_ENTRY(") >= 0: # a function prototype
-            returnType = line[0: line.find(" API_ENTRY(")]
-            functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
-            parameterList = line[line.find(")(") + 2: line.find(") {")]
-            
-            #if line.find("*") >= 0:
-            #    extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)
-            #    externs.append(extern)
-            #    continue
-            
-            if functionName in skipFunctions:
-                sys.stderr.write("!\n! skipping function '%s'\n!\n" % functionName)
-                continue
-            output += "\
-    case glesv2debugger::Message_Function_%s:\n" % functionName
-            parameters = parameterList.split(',')
-            paramIndex = 0
-            if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer
-                # add function to list of functions that should be hand written, but generate code anyways
-                externs.append(functionName)
-                output += "\
-        ret = GenerateCall_%s(dbg, cmd, msg, prevRet);\n\
-        break;\n" % (functionName)
-                continue
-            elif line.find(":out") >= 0 or line.find(":inout") >= 0:
-                externs.append(functionName)
-                output += "\
-        ret = GenerateCall_%s(dbg, cmd, msg, prevRet);\n\
-        break; // annotated output pointers\n" % (functionName)
-                continue
-                
-            if parameterList == "void":
-                parameters = []
-            arguments = ""
-            paramNames = []
-            inout = ""
-            getData = ""
-            
-            callerMembers = ""
-
-            for parameter in parameters:
-                const = parameter.find("const")
-                parameter = parameter.replace("const", "")
-                parameter = parameter.strip()
-                paramType = parameter.split(' ')[0]
-                paramName = parameter.split(' ')[1]
-                annotation = ""
-                if parameter.find(":") >= 0: # has annotation
-                    assert inout == "" # only one parameter should be annotated
-                    sys.stderr.write("%s is annotated: %s \n" % (functionName, paramType))
-                    inout = paramType.split(":")[2]
-                    annotation = paramType.split(":")[1]
-                    paramType = paramType.split(":")[0]
-                    count = 1
-                    countArg = ""
-                    if annotation.find("*") >= 0: # [1,n] * param
-                        count = int(annotation.split("*")[0])
-                        countArg = annotation.split("*")[1]
-                        assert countArg in paramNames
-                    elif annotation in paramNames:
-                        count = 1
-                        countArg = annotation
-                    elif annotation == "GLstring":
-                        annotation = "strlen(%s)" % (paramName)
-                    else:
-                        count = int(annotation)
-            
-                    paramType += "*"
-                    arguments += "reinterpret_cast<%s>(const_cast<char *>(cmd.data().data()))" % (paramType)
-                elif paramType == "GLboolean":
-                    arguments += "GLboolean(cmd.arg%d())" % (paramIndex)
-                else:
-                    arguments += "static_cast<%s>(cmd.arg%d())" % (paramType, paramIndex)
-
-                if paramIndex < len(parameters) - 1:
-                        arguments += ", "
-                if len(arguments) - arguments.rfind("\n") > 60 :
-                    arguments += "\n\
-            "
-                if const >= 0:
-                    paramType = "const " + paramType
-                paramNames.append(paramName)
-                paramIndex += 1
-                
-            if returnType == "void":
-                output += "\
-        dbg->hooks->gl.%s(\n\
-            %s);\n\
-        break;\n" % (functionName, arguments)
-            else:
-                output += "\
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.%s(\n\
-            %s)));\n\
-        if (cmd.has_ret())\n\
-            ret = reinterpret_cast<int *>(msg.ret());\n\
-        break;\n" % (functionName, arguments)
-    return output
-
-if __name__ == "__main__":
-
-    lines = open("gl2_api_annotated.in").readlines()
-    output = generate_caller(lines)
-    
-    out = open("src/caller.cpp", "w")
-    out.write("""\
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-// auto generated by generate_caller_cpp.py
-// implement declarations in caller.h
-
-#include "header.h"
-
-namespace android {
-
-""")
-
-    for extern in externs:
-        out.write("\
-static const int * GenerateCall_%s(DbgContext * const dbg,\n\
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);\n" % (extern))
-        print("\
-static const int * GenerateCall_%s(DbgContext * const dbg,\n\
-                            const glesv2debugger::Message & cmd,\n\
-                            glesv2debugger::Message & msg, const int * const prevRet)\n\
-{ assert(0); return prevRet; }\n" % (extern))
-                     
-    out.write(
-"""
-#include "caller.h"
-
-const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
-                  glesv2debugger::Message & msg, const int * const prevRet)
-{
-    LOGD("GenerateCall function=%u", cmd.function());
-    const int * ret = prevRet; // only some functions have return value
-    nsecs_t c0 = systemTime(timeMode);
-    switch (cmd.function()) {""")
-    
-    out.write(output)
-    
-    out.write("""\
-    default:
-        assert(0);
-    }
-    msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-    msg.set_context_id(reinterpret_cast<int>(dbg));
-    msg.set_function(cmd.function());
-    msg.set_type(glesv2debugger::Message_Type_AfterCall);
-    return ret;
-}
-
-}; // name space android {
-""")           
-    
-            
diff --git a/opengl/libs/GLES2_dbg/generate_debug_in.py b/opengl/libs/GLES2_dbg/generate_debug_in.py
deleted file mode 100755
index 1280c6f..0000000
--- a/opengl/libs/GLES2_dbg/generate_debug_in.py
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-#
-# Copyright 2011, The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-import os
-import sys
-
-def append_functions(functions, lines):
-	i = 0
-	for line in lines:
-		if line.find("API_ENTRY(") >= 0: # a function prototype
-			returnType = line[0: line.find(" API_ENTRY(")]
-			functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
-			parameterList = line[line.find(")(") + 2: line.find(") {")]
-			
-			functions.append(functionName)
-			#print functionName
-			continue
-				
-			parameters = parameterList.split(',')
-			paramIndex = 0
-			if line.find("*") >= 0:
-				print "// FIXME: this function has pointers, it should be hand written"
-				externs.append("%s Tracing_%s(%s);" % (returnType, functionName, parameterList))
-			print "%s Tracing_%s(%s)\n{" % (returnType, functionName, parameterList)
-			
-			if parameterList == "void":
-				parameters = []
-			
-			arguments = ""
-			 
-			for parameter in parameters:
-				parameter = parameter.replace("const", "")
-				parameter = parameter.strip()
-				paramType = parameter.split(' ')[0]
-				paramName = parameter.split(' ')[1]
-				
-				paramIndex += 1
-				
-	return functions
-	
-
-
-if __name__ == "__main__":
-	definedFunctions = []
-	lines = open("gl2_api_annotated.in").readlines()
-	definedFunctions = append_functions(definedFunctions, lines)
-	
-	output = open("../debug.in", "w")
-	lines = open("../trace.in").readlines()
-	output.write("// the following functions are not defined in GLESv2_dbg\n")
-	for line in lines:
-		functionName = ""
-		if line.find("TRACE_GL(") >= 0: # a function prototype
-			functionName = line.split(',')[1].strip()
-		elif line.find("TRACE_GL_VOID(") >= 0: # a function prototype
-			functionName = line[line.find("(") + 1: line.find(",")] #extract GL function name
-		else:
-			continue
-		if functionName in definedFunctions:
-			#print functionName
-			continue
-		else:
-			output.write(line)
-	
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
deleted file mode 100755
index 535b13e..0000000
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-#
-# Copyright 2011, The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-import os
-
-def generate_egl_entries(output, lines, i):
-    for line in lines:
-        if line.find("EGL_ENTRY(") >= 0:
-            line = line.split(",")[1].strip() #extract EGL function name
-            output.write("        %s = %d;\n" % (line, i))
-            i += 1
-    return i
-
-
-def generate_gl_entries(output,lines,i):
-    for line in lines:
-        if line.find("API_ENTRY(") >= 0:
-            line = line[line.find("(") + 1: line.find(")")] #extract GL function name
-            output.write("        %s = %d;\n" % (line, i))
-            i += 1
-    return i
-
-
-if __name__ == "__main__":
-    output = open("debugger_message.proto",'w')
-    output.write("""\
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// do not edit; auto generated by generate_debugger_message_proto.py
-
-package com.android.glesv2debugger;
-
-option optimize_for = LITE_RUNTIME;
-
-message Message
-{
-    required int32 context_id = 1; // GL context id
-    enum Function
-    {
-""")
-
-    i = 0;
-
-    lines = open("gl2_api_annotated.in").readlines()
-    i = generate_gl_entries(output, lines, i)
-    output.write("        // end of GL functions\n")
-
-    #lines = open("gl2ext_api.in").readlines()
-    #i = generate_gl_entries(output, lines, i)
-    #output.write("        // end of GL EXT functions\n")
-
-    lines = open("../EGL/egl_entries.in").readlines()
-    i = generate_egl_entries(output, lines, i)
-    output.write("        // end of GL EXT functions\n")
-
-    output.write("        ACK = %d;\n" % (i))
-    i += 1
-
-    output.write("        NEG = %d;\n" % (i))
-    i += 1
-
-    output.write("        CONTINUE = %d;\n" % (i))
-    i += 1
-
-    output.write("        SKIP = %d;\n" % (i))
-    i += 1
-
-    output.write("        SETPROP = %d;\n" % (i))
-    i += 1
-
-    output.write("""    }
-    required Function function = 2 [default = NEG]; // type/function of message
-    enum Type
-    {
-        BeforeCall = 0;
-        AfterCall = 1;
-        AfterGeneratedCall = 2;
-        Response = 3; // currently used for misc messages
-        CompleteCall = 4; // BeforeCall and AfterCall merged
-    }
-    required Type type = 3;
-    required bool expect_response = 4;
-    optional int32 ret = 5; // return value from previous GL call
-    optional int32 arg0 = 6; // args to GL call
-    optional int32 arg1 = 7;
-    optional int32 arg2 = 8;
-    optional int32 arg3 = 9;
-    optional int32 arg4 = 16;
-    optional int32 arg5 = 17;
-    optional int32 arg6 = 18;
-    optional int32 arg7 = 19; // glDrawArrays/Elements sets this to active number of attributes
-    optional int32 arg8 = 20;
-
-    optional bytes data = 10; // variable length data used for GL call
-    enum DataType
-    {
-        ReferencedImage = 0; // for image sourced from ReadPixels
-        NonreferencedImage = 1; // for image sourced from ReadPixels
-    };
-    // most data types can be inferred from function
-    optional DataType data_type = 23;
-    // these are used for image data when they cannot be determined from args
-    optional int32 pixel_format = 24;
-    optional int32 pixel_type = 25;
-    optional int32 image_width = 26;
-    optional int32 image_height = 27;
-
-    optional float time = 11; // duration of previous GL call (ms)
-    enum Prop
-    {
-        CaptureDraw = 0; // arg0 = number of glDrawArrays/Elements to glReadPixels
-        TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h
-        ExpectResponse = 2; // arg0 = enum Function, arg1 = true/false
-        CaptureSwap = 3; // arg0 = number of eglSwapBuffers to glReadPixels
-        GLConstant = 4; // arg0 = GLenum, arg1 = constant; send GL impl. constants
-    };
-    optional Prop prop = 21; // used with SETPROP, value in arg0
-    optional float clock = 22; // wall clock in seconds
-}
-""")
-
-    output.close()
-
-    os.system("aprotoc --cpp_out=src --java_out=../../../../../development/tools/glesv2debugger/src debugger_message.proto")
-    os.system('mv -f "src/debugger_message.pb.cc" "src/debugger_message.pb.cpp"')
diff --git a/opengl/libs/GLES2_dbg/gl2_api_annotated.in b/opengl/libs/GLES2_dbg/gl2_api_annotated.in
deleted file mode 100644
index 227e2eb..0000000
--- a/opengl/libs/GLES2_dbg/gl2_api_annotated.in
+++ /dev/null
@@ -1,426 +0,0 @@
-void API_ENTRY(glActiveTexture)(GLenum texture) {
-    CALL_GL_API(glActiveTexture, texture);
-}
-void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) {
-    CALL_GL_API(glAttachShader, program, shader);
-}
-void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const GLchar:GLstring:in name) {
-    CALL_GL_API(glBindAttribLocation, program, index, name);
-}
-void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
-    CALL_GL_API(glBindBuffer, target, buffer);
-}
-void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) {
-    CALL_GL_API(glBindFramebuffer, target, framebuffer);
-}
-void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) {
-    CALL_GL_API(glBindRenderbuffer, target, renderbuffer);
-}
-void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
-    CALL_GL_API(glBindTexture, target, texture);
-}
-void API_ENTRY(glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
-    CALL_GL_API(glBlendColor, red, green, blue, alpha);
-}
-void API_ENTRY(glBlendEquation)( GLenum mode ) {
-    CALL_GL_API(glBlendEquation, mode);
-}
-void API_ENTRY(glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) {
-    CALL_GL_API(glBlendEquationSeparate, modeRGB, modeAlpha);
-}
-void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
-    CALL_GL_API(glBlendFunc, sfactor, dfactor);
-}
-void API_ENTRY(glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
-    CALL_GL_API(glBlendFuncSeparate, srcRGB, dstRGB, srcAlpha, dstAlpha);
-}
-void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid:size:in data, GLenum usage) {
-    CALL_GL_API(glBufferData, target, size, data, usage);
-}
-void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid:size:in data) {
-    CALL_GL_API(glBufferSubData, target, offset, size, data);
-}
-GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) {
-    CALL_GL_API_RETURN(glCheckFramebufferStatus, target);
-}
-void API_ENTRY(glClear)(GLbitfield mask) {
-    CALL_GL_API(glClear, mask);
-}
-void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
-    CALL_GL_API(glClearColor, red, green, blue, alpha);
-}
-void API_ENTRY(glClearDepthf)(GLclampf depth) {
-    CALL_GL_API(glClearDepthf, depth);
-}
-void API_ENTRY(glClearStencil)(GLint s) {
-    CALL_GL_API(glClearStencil, s);
-}
-void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
-    CALL_GL_API(glColorMask, red, green, blue, alpha);
-}
-void API_ENTRY(glCompileShader)(GLuint shader) {
-    CALL_GL_API(glCompileShader, shader);
-}
-void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) {
-    CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
-}
-void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) {
-    CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
-}
-void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
-    CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border);
-}
-void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
-    CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height);
-}
-GLuint API_ENTRY(glCreateProgram)(void) {
-    CALL_GL_API_RETURN(glCreateProgram);
-}
-GLuint API_ENTRY(glCreateShader)(GLenum type) {
-    CALL_GL_API_RETURN(glCreateShader, type);
-}
-void API_ENTRY(glCullFace)(GLenum mode) {
-    CALL_GL_API(glCullFace, mode);
-}
-void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint:n:in buffers) {
-    CALL_GL_API(glDeleteBuffers, n, buffers);
-}
-void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint:n:in framebuffers) {
-    CALL_GL_API(glDeleteFramebuffers, n, framebuffers);
-}
-void API_ENTRY(glDeleteProgram)(GLuint program) {
-    CALL_GL_API(glDeleteProgram, program);
-}
-void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint:n:in renderbuffers) {
-    CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers);
-}
-void API_ENTRY(glDeleteShader)(GLuint shader) {
-    CALL_GL_API(glDeleteShader, shader);
-}
-void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint:n:in textures) {
-    CALL_GL_API(glDeleteTextures, n, textures);
-}
-void API_ENTRY(glDepthFunc)(GLenum func) {
-    CALL_GL_API(glDepthFunc, func);
-}
-void API_ENTRY(glDepthMask)(GLboolean flag) {
-    CALL_GL_API(glDepthMask, flag);
-}
-void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
-    CALL_GL_API(glDepthRangef, zNear, zFar);
-}
-void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) {
-    CALL_GL_API(glDetachShader, program, shader);
-}
-void API_ENTRY(glDisable)(GLenum cap) {
-    CALL_GL_API(glDisable, cap);
-}
-void API_ENTRY(glDisableVertexAttribArray)(GLuint index) {
-    CALL_GL_API(glDisableVertexAttribArray, index);
-}
-void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
-    CALL_GL_API(glDrawArrays, mode, first, count);
-}
-void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) {
-    CALL_GL_API(glDrawElements, mode, count, type, indices);
-}
-void API_ENTRY(glEnable)(GLenum cap) {
-    CALL_GL_API(glEnable, cap);
-}
-void API_ENTRY(glEnableVertexAttribArray)(GLuint index) {
-    CALL_GL_API(glEnableVertexAttribArray, index);
-}
-void API_ENTRY(glFinish)(void) {
-    CALL_GL_API(glFinish);
-}
-void API_ENTRY(glFlush)(void) {
-    CALL_GL_API(glFlush);
-}
-void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
-    CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer);
-}
-void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
-    CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level);
-}
-void API_ENTRY(glFrontFace)(GLenum mode) {
-    CALL_GL_API(glFrontFace, mode);
-}
-void API_ENTRY(glGenBuffers)(GLsizei n, GLuint:n:out buffers) {
-    CALL_GL_API(glGenBuffers, n, buffers);
-}
-void API_ENTRY(glGenerateMipmap)(GLenum target) {
-    CALL_GL_API(glGenerateMipmap, target);
-}
-void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint:n:out framebuffers) {
-    CALL_GL_API(glGenFramebuffers, n, framebuffers);
-}
-void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint:n:out renderbuffers) {
-    CALL_GL_API(glGenRenderbuffers, n, renderbuffers);
-}
-void API_ENTRY(glGenTextures)(GLsizei n, GLuint:n:out textures) {
-    CALL_GL_API(glGenTextures, n, textures);
-}
-void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar:GLstring:in name) {
-    CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name);
-}
-void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar:GLstring:in name) {
-    CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name);
-}
-void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
-    CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders);
-}
-int API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar:GLstring:in name) {
-    CALL_GL_API_RETURN(glGetAttribLocation, program, name);
-}
-void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params) {
-    CALL_GL_API(glGetBooleanv, pname, params);
-}
-void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
-    CALL_GL_API(glGetBufferParameteriv, target, pname, params);
-}
-GLenum API_ENTRY(glGetError)(void) {
-    CALL_GL_API_RETURN(glGetError);
-}
-void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params) {
-    CALL_GL_API(glGetFloatv, pname, params);
-}
-void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params) {
-    CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
-}
-void API_ENTRY(glGetIntegerv)(GLenum pname, GLint* params) {
-    CALL_GL_API(glGetIntegerv, pname, params);
-}
-void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint:1:out params) {
-    CALL_GL_API(glGetProgramiv, program, pname, params);
-}
-void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out infolog) {
-    CALL_GL_API(glGetProgramInfoLog, program, bufsize, length, infolog);
-}
-void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
-    CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params);
-}
-void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint:1:out params) {
-    CALL_GL_API(glGetShaderiv, shader, pname, params);
-}
-void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out infolog) {
-    CALL_GL_API(glGetShaderInfoLog, shader, bufsize, length, infolog);
-}
-void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
-    CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision);
-}
-void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out source) {
-    CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
-}
-const GLubyte* API_ENTRY(glGetString)(GLenum name) {
-    CALL_GL_API_RETURN(glGetString, name);
-}
-void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) {
-    CALL_GL_API(glGetTexParameterfv, target, pname, params);
-}
-void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params) {
-    CALL_GL_API(glGetTexParameteriv, target, pname, params);
-}
-void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params) {
-    CALL_GL_API(glGetUniformfv, program, location, params);
-}
-void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params) {
-    CALL_GL_API(glGetUniformiv, program, location, params);
-}
-int API_ENTRY(glGetUniformLocation)(GLuint program, const GLchar:GLstring:in name) {
-    CALL_GL_API_RETURN(glGetUniformLocation, program, name);
-}
-void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) {
-    CALL_GL_API(glGetVertexAttribfv, index, pname, params);
-}
-void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) {
-    CALL_GL_API(glGetVertexAttribiv, index, pname, params);
-}
-void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer) {
-    CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer);
-}
-void API_ENTRY(glHint)(GLenum target, GLenum mode) {
-    CALL_GL_API(glHint, target, mode);
-}
-GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
-    CALL_GL_API_RETURN(glIsBuffer, buffer);
-}
-GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
-    CALL_GL_API_RETURN(glIsEnabled, cap);
-}
-GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) {
-    CALL_GL_API_RETURN(glIsFramebuffer, framebuffer);
-}
-GLboolean API_ENTRY(glIsProgram)(GLuint program) {
-    CALL_GL_API_RETURN(glIsProgram, program);
-}
-GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) {
-    CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer);
-}
-GLboolean API_ENTRY(glIsShader)(GLuint shader) {
-    CALL_GL_API_RETURN(glIsShader, shader);
-}
-GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
-    CALL_GL_API_RETURN(glIsTexture, texture);
-}
-void API_ENTRY(glLineWidth)(GLfloat width) {
-    CALL_GL_API(glLineWidth, width);
-}
-void API_ENTRY(glLinkProgram)(GLuint program) {
-    CALL_GL_API(glLinkProgram, program);
-}
-void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
-    CALL_GL_API(glPixelStorei, pname, param);
-}
-void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
-    CALL_GL_API(glPolygonOffset, factor, units);
-}
-void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) {
-    CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
-}
-void API_ENTRY(glReleaseShaderCompiler)(void) {
-    CALL_GL_API(glReleaseShaderCompiler);
-}
-void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
-    CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height);
-}
-void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
-    CALL_GL_API(glSampleCoverage, value, invert);
-}
-void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
-    CALL_GL_API(glScissor, x, y, width, height);
-}
-void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) {
-    CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length);
-}
-void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) {
-    CALL_GL_API(glShaderSource, shader, count, string, length);
-}
-void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
-    CALL_GL_API(glStencilFunc, func, ref, mask);
-}
-void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) {
-    CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask);
-}
-void API_ENTRY(glStencilMask)(GLuint mask) {
-    CALL_GL_API(glStencilMask, mask);
-}
-void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) {
-    CALL_GL_API(glStencilMaskSeparate, face, mask);
-}
-void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
-    CALL_GL_API(glStencilOp, fail, zfail, zpass);
-}
-void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
-    CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass);
-}
-void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) {
-    CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels);
-}
-void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
-    CALL_GL_API(glTexParameterf, target, pname, param);
-}
-void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params) {
-    CALL_GL_API(glTexParameterfv, target, pname, params);
-}
-void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
-    CALL_GL_API(glTexParameteri, target, pname, param);
-}
-void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) {
-    CALL_GL_API(glTexParameteriv, target, pname, params);
-}
-void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) {
-    CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels);
-}
-void API_ENTRY(glUniform1f)(GLint location, GLfloat x) {
-    CALL_GL_API(glUniform1f, location, x);
-}
-void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat:1*count:in v) {
-    CALL_GL_API(glUniform1fv, location, count, v);
-}
-void API_ENTRY(glUniform1i)(GLint location, GLint x) {
-    CALL_GL_API(glUniform1i, location, x);
-}
-void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint:1*count:in v) {
-    CALL_GL_API(glUniform1iv, location, count, v);
-}
-void API_ENTRY(glUniform2f)(GLint location, GLfloat x, GLfloat y) {
-    CALL_GL_API(glUniform2f, location, x, y);
-}
-void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat:2*count:in v) {
-    CALL_GL_API(glUniform2fv, location, count, v);
-}
-void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y) {
-    CALL_GL_API(glUniform2i, location, x, y);
-}
-void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint:2*count:in v) {
-    CALL_GL_API(glUniform2iv, location, count, v);
-}
-void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) {
-    CALL_GL_API(glUniform3f, location, x, y, z);
-}
-void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat:3*count:in v) {
-    CALL_GL_API(glUniform3fv, location, count, v);
-}
-void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z) {
-    CALL_GL_API(glUniform3i, location, x, y, z);
-}
-void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint:3*count:in v) {
-    CALL_GL_API(glUniform3iv, location, count, v);
-}
-void API_ENTRY(glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
-    CALL_GL_API(glUniform4f, location, x, y, z, w);
-}
-void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat:4*count:in v) {
-    CALL_GL_API(glUniform4fv, location, count, v);
-}
-void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w) {
-    CALL_GL_API(glUniform4i, location, x, y, z, w);
-}
-void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint:4*count:in v) {
-    CALL_GL_API(glUniform4iv, location, count, v);
-}
-void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:4*count:in value) {
-    CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value);
-}
-void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:9*count:in value) {
-    CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value);
-}
-void API_ENTRY(glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:16*count:in value) {
-    CALL_GL_API(glUniformMatrix4fv, location, count, transpose, value);
-}
-void API_ENTRY(glUseProgram)(GLuint program) {
-    CALL_GL_API(glUseProgram, program);
-}
-void API_ENTRY(glValidateProgram)(GLuint program) {
-    CALL_GL_API(glValidateProgram, program);
-}
-void API_ENTRY(glVertexAttrib1f)(GLuint indx, GLfloat x) {
-    CALL_GL_API(glVertexAttrib1f, indx, x);
-}
-void API_ENTRY(glVertexAttrib1fv)(GLuint indx, const GLfloat:1:in values) {
-    CALL_GL_API(glVertexAttrib1fv, indx, values);
-}
-void API_ENTRY(glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y) {
-    CALL_GL_API(glVertexAttrib2f, indx, x, y);
-}
-void API_ENTRY(glVertexAttrib2fv)(GLuint indx, const GLfloat:2:in values) {
-    CALL_GL_API(glVertexAttrib2fv, indx, values);
-}
-void API_ENTRY(glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
-    CALL_GL_API(glVertexAttrib3f, indx, x, y, z);
-}
-void API_ENTRY(glVertexAttrib3fv)(GLuint indx, const GLfloat:3:in values) {
-    CALL_GL_API(glVertexAttrib3fv, indx, values);
-}
-void API_ENTRY(glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
-    CALL_GL_API(glVertexAttrib4f, indx, x, y, z, w);
-}
-void API_ENTRY(glVertexAttrib4fv)(GLuint indx, const GLfloat:4:in values) {
-    CALL_GL_API(glVertexAttrib4fv, indx, values);
-}
-void API_ENTRY(glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) {
-    CALL_GL_API(glVertexAttribPointer, indx, size, type, normalized, stride, ptr);
-}
-void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
-    CALL_GL_API(glViewport, x, y, width, height);
-}
diff --git a/opengl/libs/GLES2_dbg/src/api.cpp b/opengl/libs/GLES2_dbg/src/api.cpp
deleted file mode 100644
index c483547..0000000
--- a/opengl/libs/GLES2_dbg/src/api.cpp
+++ /dev/null
@@ -1,3540 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
- 
-// auto generated by generate_api_cpp.py
-
-#include <utils/Debug.h>
-
-#include "src/header.h"
-#include "src/api.h"
-
-template<typename T> static int ToInt(const T & t)
-{
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
-    return (int &)t;
-}
-
-void Debug_glActiveTexture(GLenum texture)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum texture;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glActiveTexture(texture);
-            return 0;
-        }
-    } caller;
-    caller.texture = texture;
-
-    msg.set_arg0(texture);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glActiveTexture);
-}
-
-void Debug_glAttachShader(GLuint program, GLuint shader)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLuint shader;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glAttachShader(program, shader);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.shader = shader;
-
-    msg.set_arg0(program);
-    msg.set_arg1(shader);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glAttachShader);
-}
-
-void Debug_glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLuint index;
-        const GLchar* name;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBindAttribLocation(program, index, name);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.index = index;
-    caller.name = name;
-
-    msg.set_arg0(program);
-    msg.set_arg1(index);
-    msg.set_arg2(ToInt(name));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindAttribLocation);
-}
-
-void Debug_glBindBuffer(GLenum target, GLuint buffer)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLuint buffer;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBindBuffer(target, buffer);
-            getDbgContextThreadSpecific()->glBindBuffer(target, buffer);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.buffer = buffer;
-
-    msg.set_arg0(target);
-    msg.set_arg1(buffer);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindBuffer);
-}
-
-void Debug_glBindFramebuffer(GLenum target, GLuint framebuffer)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLuint framebuffer;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBindFramebuffer(target, framebuffer);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.framebuffer = framebuffer;
-
-    msg.set_arg0(target);
-    msg.set_arg1(framebuffer);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindFramebuffer);
-}
-
-void Debug_glBindRenderbuffer(GLenum target, GLuint renderbuffer)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLuint renderbuffer;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBindRenderbuffer(target, renderbuffer);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.renderbuffer = renderbuffer;
-
-    msg.set_arg0(target);
-    msg.set_arg1(renderbuffer);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindRenderbuffer);
-}
-
-void Debug_glBindTexture(GLenum target, GLuint texture)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLuint texture;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBindTexture(target, texture);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.texture = texture;
-
-    msg.set_arg0(target);
-    msg.set_arg1(texture);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindTexture);
-}
-
-void Debug_glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLclampf red;
-        GLclampf green;
-        GLclampf blue;
-        GLclampf alpha;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBlendColor(red, green, blue, alpha);
-            return 0;
-        }
-    } caller;
-    caller.red = red;
-    caller.green = green;
-    caller.blue = blue;
-    caller.alpha = alpha;
-
-    msg.set_arg0(ToInt(red));
-    msg.set_arg1(ToInt(green));
-    msg.set_arg2(ToInt(blue));
-    msg.set_arg3(ToInt(alpha));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendColor);
-}
-
-void Debug_glBlendEquation( GLenum mode )
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum mode;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBlendEquation(mode);
-            return 0;
-        }
-    } caller;
-    caller.mode = mode;
-
-    msg.set_arg0(mode);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendEquation);
-}
-
-void Debug_glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum modeRGB;
-        GLenum modeAlpha;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBlendEquationSeparate(modeRGB, modeAlpha);
-            return 0;
-        }
-    } caller;
-    caller.modeRGB = modeRGB;
-    caller.modeAlpha = modeAlpha;
-
-    msg.set_arg0(modeRGB);
-    msg.set_arg1(modeAlpha);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendEquationSeparate);
-}
-
-void Debug_glBlendFunc(GLenum sfactor, GLenum dfactor)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum sfactor;
-        GLenum dfactor;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBlendFunc(sfactor, dfactor);
-            return 0;
-        }
-    } caller;
-    caller.sfactor = sfactor;
-    caller.dfactor = dfactor;
-
-    msg.set_arg0(sfactor);
-    msg.set_arg1(dfactor);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendFunc);
-}
-
-void Debug_glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum srcRGB;
-        GLenum dstRGB;
-        GLenum srcAlpha;
-        GLenum dstAlpha;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
-            return 0;
-        }
-    } caller;
-    caller.srcRGB = srcRGB;
-    caller.dstRGB = dstRGB;
-    caller.srcAlpha = srcAlpha;
-    caller.dstAlpha = dstAlpha;
-
-    msg.set_arg0(srcRGB);
-    msg.set_arg1(dstRGB);
-    msg.set_arg2(srcAlpha);
-    msg.set_arg3(dstAlpha);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendFuncSeparate);
-}
-
-void Debug_glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLsizeiptr size;
-        const GLvoid* data;
-        GLenum usage;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBufferData(target, size, data, usage);
-            getDbgContextThreadSpecific()->glBufferData(target, size, data, usage);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.size = size;
-    caller.data = data;
-    caller.usage = usage;
-
-    msg.set_arg0(target);
-    msg.set_arg1(size);
-    msg.set_arg2(ToInt(data));
-    msg.set_arg3(usage);
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBufferData);
-}
-
-void Debug_glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLintptr offset;
-        GLsizeiptr size;
-        const GLvoid* data;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glBufferSubData(target, offset, size, data);
-            getDbgContextThreadSpecific()->glBufferSubData(target, offset, size, data);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.offset = offset;
-    caller.size = size;
-    caller.data = data;
-
-    msg.set_arg0(target);
-    msg.set_arg1(offset);
-    msg.set_arg2(size);
-    msg.set_arg3(ToInt(data));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBufferSubData);
-}
-
-GLenum Debug_glCheckFramebufferStatus(GLenum target)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glCheckFramebufferStatus(target));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.target = target;
-
-    msg.set_arg0(target);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCheckFramebufferStatus);
-    return reinterpret_cast<GLenum>(ret);
-}
-
-void Debug_glClear(GLbitfield mask)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLbitfield mask;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glClear(mask);
-            return 0;
-        }
-    } caller;
-    caller.mask = mask;
-
-    msg.set_arg0(mask);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClear);
-}
-
-void Debug_glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLclampf red;
-        GLclampf green;
-        GLclampf blue;
-        GLclampf alpha;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glClearColor(red, green, blue, alpha);
-            return 0;
-        }
-    } caller;
-    caller.red = red;
-    caller.green = green;
-    caller.blue = blue;
-    caller.alpha = alpha;
-
-    msg.set_arg0(ToInt(red));
-    msg.set_arg1(ToInt(green));
-    msg.set_arg2(ToInt(blue));
-    msg.set_arg3(ToInt(alpha));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearColor);
-}
-
-void Debug_glClearDepthf(GLclampf depth)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLclampf depth;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glClearDepthf(depth);
-            return 0;
-        }
-    } caller;
-    caller.depth = depth;
-
-    msg.set_arg0(ToInt(depth));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearDepthf);
-}
-
-void Debug_glClearStencil(GLint s)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint s;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glClearStencil(s);
-            return 0;
-        }
-    } caller;
-    caller.s = s;
-
-    msg.set_arg0(s);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearStencil);
-}
-
-void Debug_glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLboolean red;
-        GLboolean green;
-        GLboolean blue;
-        GLboolean alpha;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glColorMask(red, green, blue, alpha);
-            return 0;
-        }
-    } caller;
-    caller.red = red;
-    caller.green = green;
-    caller.blue = blue;
-    caller.alpha = alpha;
-
-    msg.set_arg0(red);
-    msg.set_arg1(green);
-    msg.set_arg2(blue);
-    msg.set_arg3(alpha);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glColorMask);
-}
-
-void Debug_glCompileShader(GLuint shader)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint shader;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glCompileShader(shader);
-            return 0;
-        }
-    } caller;
-    caller.shader = shader;
-
-    msg.set_arg0(shader);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompileShader);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLint level;
-        GLenum internalformat;
-        GLsizei width;
-        GLsizei height;
-        GLint border;
-        GLsizei imageSize;
-        const GLvoid* data;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.level = level;
-    caller.internalformat = internalformat;
-    caller.width = width;
-    caller.height = height;
-    caller.border = border;
-    caller.imageSize = imageSize;
-    caller.data = data;
-
-    msg.set_arg0(target);
-    msg.set_arg1(level);
-    msg.set_arg2(internalformat);
-    msg.set_arg3(width);
-    msg.set_arg4(height);
-    msg.set_arg5(border);
-    msg.set_arg6(imageSize);
-    msg.set_arg7(ToInt(data));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompressedTexImage2D);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLint level;
-        GLint xoffset;
-        GLint yoffset;
-        GLsizei width;
-        GLsizei height;
-        GLenum format;
-        GLsizei imageSize;
-        const GLvoid* data;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.level = level;
-    caller.xoffset = xoffset;
-    caller.yoffset = yoffset;
-    caller.width = width;
-    caller.height = height;
-    caller.format = format;
-    caller.imageSize = imageSize;
-    caller.data = data;
-
-    msg.set_arg0(target);
-    msg.set_arg1(level);
-    msg.set_arg2(xoffset);
-    msg.set_arg3(yoffset);
-    msg.set_arg4(width);
-    msg.set_arg5(height);
-    msg.set_arg6(format);
-    msg.set_arg7(imageSize);
-    msg.set_arg8(ToInt(data));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompressedTexSubImage2D);
-}
-
-void Debug_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLint level;
-        GLenum internalformat;
-        GLint x;
-        GLint y;
-        GLsizei width;
-        GLsizei height;
-        GLint border;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
-#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexImage2D
-            EXTEND_AFTER_CALL_Debug_glCopyTexImage2D;
-#endif
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.level = level;
-    caller.internalformat = internalformat;
-    caller.x = x;
-    caller.y = y;
-    caller.width = width;
-    caller.height = height;
-    caller.border = border;
-
-    msg.set_arg0(target);
-    msg.set_arg1(level);
-    msg.set_arg2(internalformat);
-    msg.set_arg3(x);
-    msg.set_arg4(y);
-    msg.set_arg5(width);
-    msg.set_arg6(height);
-    msg.set_arg7(border);
-
-#ifdef EXTEND_Debug_glCopyTexImage2D
-    EXTEND_Debug_glCopyTexImage2D;
-#endif
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexImage2D);
-}
-
-void Debug_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLint level;
-        GLint xoffset;
-        GLint yoffset;
-        GLint x;
-        GLint y;
-        GLsizei width;
-        GLsizei height;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
-#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D
-            EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D;
-#endif
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.level = level;
-    caller.xoffset = xoffset;
-    caller.yoffset = yoffset;
-    caller.x = x;
-    caller.y = y;
-    caller.width = width;
-    caller.height = height;
-
-    msg.set_arg0(target);
-    msg.set_arg1(level);
-    msg.set_arg2(xoffset);
-    msg.set_arg3(yoffset);
-    msg.set_arg4(x);
-    msg.set_arg5(y);
-    msg.set_arg6(width);
-    msg.set_arg7(height);
-
-#ifdef EXTEND_Debug_glCopyTexSubImage2D
-    EXTEND_Debug_glCopyTexSubImage2D;
-#endif
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexSubImage2D);
-}
-
-GLuint Debug_glCreateProgram(void)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glCreateProgram());
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCreateProgram);
-    return reinterpret_cast<GLuint>(ret);
-}
-
-GLuint Debug_glCreateShader(GLenum type)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum type;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glCreateShader(type));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.type = type;
-
-    msg.set_arg0(type);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCreateShader);
-    return reinterpret_cast<GLuint>(ret);
-}
-
-void Debug_glCullFace(GLenum mode)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum mode;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glCullFace(mode);
-            return 0;
-        }
-    } caller;
-    caller.mode = mode;
-
-    msg.set_arg0(mode);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCullFace);
-}
-
-void Debug_glDeleteBuffers(GLsizei n, const GLuint* buffers)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLsizei n;
-        const GLuint* buffers;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDeleteBuffers(n, buffers);
-            getDbgContextThreadSpecific()->glDeleteBuffers(n, buffers);
-            return 0;
-        }
-    } caller;
-    caller.n = n;
-    caller.buffers = buffers;
-
-    msg.set_arg0(n);
-    msg.set_arg1(ToInt(buffers));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(buffers), n * sizeof(GLuint));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteBuffers);
-}
-
-void Debug_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLsizei n;
-        const GLuint* framebuffers;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDeleteFramebuffers(n, framebuffers);
-            return 0;
-        }
-    } caller;
-    caller.n = n;
-    caller.framebuffers = framebuffers;
-
-    msg.set_arg0(n);
-    msg.set_arg1(ToInt(framebuffers));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(framebuffers), n * sizeof(GLuint));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteFramebuffers);
-}
-
-void Debug_glDeleteProgram(GLuint program)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDeleteProgram(program);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-
-    msg.set_arg0(program);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteProgram);
-}
-
-void Debug_glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLsizei n;
-        const GLuint* renderbuffers;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDeleteRenderbuffers(n, renderbuffers);
-            return 0;
-        }
-    } caller;
-    caller.n = n;
-    caller.renderbuffers = renderbuffers;
-
-    msg.set_arg0(n);
-    msg.set_arg1(ToInt(renderbuffers));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(renderbuffers), n * sizeof(GLuint));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteRenderbuffers);
-}
-
-void Debug_glDeleteShader(GLuint shader)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint shader;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDeleteShader(shader);
-            return 0;
-        }
-    } caller;
-    caller.shader = shader;
-
-    msg.set_arg0(shader);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteShader);
-}
-
-void Debug_glDeleteTextures(GLsizei n, const GLuint* textures)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLsizei n;
-        const GLuint* textures;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDeleteTextures(n, textures);
-            return 0;
-        }
-    } caller;
-    caller.n = n;
-    caller.textures = textures;
-
-    msg.set_arg0(n);
-    msg.set_arg1(ToInt(textures));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(textures), n * sizeof(GLuint));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteTextures);
-}
-
-void Debug_glDepthFunc(GLenum func)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum func;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDepthFunc(func);
-            return 0;
-        }
-    } caller;
-    caller.func = func;
-
-    msg.set_arg0(func);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthFunc);
-}
-
-void Debug_glDepthMask(GLboolean flag)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLboolean flag;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDepthMask(flag);
-            return 0;
-        }
-    } caller;
-    caller.flag = flag;
-
-    msg.set_arg0(flag);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthMask);
-}
-
-void Debug_glDepthRangef(GLclampf zNear, GLclampf zFar)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLclampf zNear;
-        GLclampf zFar;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDepthRangef(zNear, zFar);
-            return 0;
-        }
-    } caller;
-    caller.zNear = zNear;
-    caller.zFar = zFar;
-
-    msg.set_arg0(ToInt(zNear));
-    msg.set_arg1(ToInt(zFar));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthRangef);
-}
-
-void Debug_glDetachShader(GLuint program, GLuint shader)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLuint shader;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDetachShader(program, shader);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.shader = shader;
-
-    msg.set_arg0(program);
-    msg.set_arg1(shader);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDetachShader);
-}
-
-void Debug_glDisable(GLenum cap)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum cap;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDisable(cap);
-            return 0;
-        }
-    } caller;
-    caller.cap = cap;
-
-    msg.set_arg0(cap);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDisable);
-}
-
-void Debug_glDisableVertexAttribArray(GLuint index)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint index;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glDisableVertexAttribArray(index);
-            getDbgContextThreadSpecific()->glDisableVertexAttribArray(index);
-            return 0;
-        }
-    } caller;
-    caller.index = index;
-
-    msg.set_arg0(index);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDisableVertexAttribArray);
-}
-
-void Debug_glEnable(GLenum cap)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum cap;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glEnable(cap);
-            return 0;
-        }
-    } caller;
-    caller.cap = cap;
-
-    msg.set_arg0(cap);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glEnable);
-}
-
-void Debug_glEnableVertexAttribArray(GLuint index)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint index;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glEnableVertexAttribArray(index);
-            getDbgContextThreadSpecific()->glEnableVertexAttribArray(index);
-            return 0;
-        }
-    } caller;
-    caller.index = index;
-
-    msg.set_arg0(index);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glEnableVertexAttribArray);
-}
-
-void Debug_glFinish(void)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glFinish();
-            return 0;
-        }
-    } caller;
-
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFinish);
-}
-
-void Debug_glFlush(void)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glFlush();
-            return 0;
-        }
-    } caller;
-
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFlush);
-}
-
-void Debug_glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum attachment;
-        GLenum renderbuffertarget;
-        GLuint renderbuffer;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.attachment = attachment;
-    caller.renderbuffertarget = renderbuffertarget;
-    caller.renderbuffer = renderbuffer;
-
-    msg.set_arg0(target);
-    msg.set_arg1(attachment);
-    msg.set_arg2(renderbuffertarget);
-    msg.set_arg3(renderbuffer);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFramebufferRenderbuffer);
-}
-
-void Debug_glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum attachment;
-        GLenum textarget;
-        GLuint texture;
-        GLint level;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glFramebufferTexture2D(target, attachment, textarget, texture, level);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.attachment = attachment;
-    caller.textarget = textarget;
-    caller.texture = texture;
-    caller.level = level;
-
-    msg.set_arg0(target);
-    msg.set_arg1(attachment);
-    msg.set_arg2(textarget);
-    msg.set_arg3(texture);
-    msg.set_arg4(level);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFramebufferTexture2D);
-}
-
-void Debug_glFrontFace(GLenum mode)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum mode;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glFrontFace(mode);
-            return 0;
-        }
-    } caller;
-    caller.mode = mode;
-
-    msg.set_arg0(mode);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFrontFace);
-}
-
-void Debug_glGenBuffers(GLsizei n, GLuint* buffers)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLsizei n;
-        GLuint* buffers;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            nsecs_t c0 = systemTime(timeMode);
-            _c->glGenBuffers(n, buffers);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.mutable_data()->assign(reinterpret_cast<const char *>(buffers), n * sizeof(GLuint));
-            return 0;
-        }
-    } caller;
-    caller.n = n;
-    caller.buffers = buffers;
-
-    msg.set_arg0(n);
-    msg.set_arg1(ToInt(buffers));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenBuffers);
-}
-
-void Debug_glGenerateMipmap(GLenum target)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGenerateMipmap(target);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-
-    msg.set_arg0(target);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenerateMipmap);
-}
-
-void Debug_glGenFramebuffers(GLsizei n, GLuint* framebuffers)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLsizei n;
-        GLuint* framebuffers;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            nsecs_t c0 = systemTime(timeMode);
-            _c->glGenFramebuffers(n, framebuffers);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.mutable_data()->assign(reinterpret_cast<const char *>(framebuffers), n * sizeof(GLuint));
-            return 0;
-        }
-    } caller;
-    caller.n = n;
-    caller.framebuffers = framebuffers;
-
-    msg.set_arg0(n);
-    msg.set_arg1(ToInt(framebuffers));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenFramebuffers);
-}
-
-void Debug_glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLsizei n;
-        GLuint* renderbuffers;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            nsecs_t c0 = systemTime(timeMode);
-            _c->glGenRenderbuffers(n, renderbuffers);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.mutable_data()->assign(reinterpret_cast<const char *>(renderbuffers), n * sizeof(GLuint));
-            return 0;
-        }
-    } caller;
-    caller.n = n;
-    caller.renderbuffers = renderbuffers;
-
-    msg.set_arg0(n);
-    msg.set_arg1(ToInt(renderbuffers));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenRenderbuffers);
-}
-
-void Debug_glGenTextures(GLsizei n, GLuint* textures)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLsizei n;
-        GLuint* textures;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            nsecs_t c0 = systemTime(timeMode);
-            _c->glGenTextures(n, textures);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.mutable_data()->assign(reinterpret_cast<const char *>(textures), n * sizeof(GLuint));
-            return 0;
-        }
-    } caller;
-    caller.n = n;
-    caller.textures = textures;
-
-    msg.set_arg0(n);
-    msg.set_arg1(ToInt(textures));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenTextures);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLuint index;
-        GLsizei bufsize;
-        GLsizei* length;
-        GLint* size;
-        GLenum* type;
-        GLchar* name;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetActiveAttrib(program, index, bufsize, length, size, type, name);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.index = index;
-    caller.bufsize = bufsize;
-    caller.length = length;
-    caller.size = size;
-    caller.type = type;
-    caller.name = name;
-
-    msg.set_arg0(program);
-    msg.set_arg1(index);
-    msg.set_arg2(bufsize);
-    msg.set_arg3(ToInt(length));
-    msg.set_arg4(ToInt(size));
-    msg.set_arg5(ToInt(type));
-    msg.set_arg6(ToInt(name));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetActiveAttrib);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLuint index;
-        GLsizei bufsize;
-        GLsizei* length;
-        GLint* size;
-        GLenum* type;
-        GLchar* name;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetActiveUniform(program, index, bufsize, length, size, type, name);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.index = index;
-    caller.bufsize = bufsize;
-    caller.length = length;
-    caller.size = size;
-    caller.type = type;
-    caller.name = name;
-
-    msg.set_arg0(program);
-    msg.set_arg1(index);
-    msg.set_arg2(bufsize);
-    msg.set_arg3(ToInt(length));
-    msg.set_arg4(ToInt(size));
-    msg.set_arg5(ToInt(type));
-    msg.set_arg6(ToInt(name));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetActiveUniform);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLsizei maxcount;
-        GLsizei* count;
-        GLuint* shaders;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetAttachedShaders(program, maxcount, count, shaders);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.maxcount = maxcount;
-    caller.count = count;
-    caller.shaders = shaders;
-
-    msg.set_arg0(program);
-    msg.set_arg1(maxcount);
-    msg.set_arg2(ToInt(count));
-    msg.set_arg3(ToInt(shaders));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetAttachedShaders);
-}
-
-int Debug_glGetAttribLocation(GLuint program, const GLchar* name)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        const GLchar* name;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glGetAttribLocation(program, name));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.program = program;
-    caller.name = name;
-
-    msg.set_arg0(program);
-    msg.set_arg1(ToInt(name));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetAttribLocation);
-    return reinterpret_cast<int>(ret);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetBooleanv(GLenum pname, GLboolean* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum pname;
-        GLboolean* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetBooleanv(pname, params);
-            return 0;
-        }
-    } caller;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(pname);
-    msg.set_arg1(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetBooleanv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum pname;
-        GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetBufferParameteriv(target, pname, params);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(target);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetBufferParameteriv);
-}
-
-GLenum Debug_glGetError(void)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glGetError());
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetError);
-    return reinterpret_cast<GLenum>(ret);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetFloatv(GLenum pname, GLfloat* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum pname;
-        GLfloat* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetFloatv(pname, params);
-            return 0;
-        }
-    } caller;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(pname);
-    msg.set_arg1(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetFloatv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum attachment;
-        GLenum pname;
-        GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.attachment = attachment;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(target);
-    msg.set_arg1(attachment);
-    msg.set_arg2(pname);
-    msg.set_arg3(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetIntegerv(GLenum pname, GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum pname;
-        GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetIntegerv(pname, params);
-            return 0;
-        }
-    } caller;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(pname);
-    msg.set_arg1(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetIntegerv);
-}
-
-void Debug_glGetProgramiv(GLuint program, GLenum pname, GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLenum pname;
-        GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            nsecs_t c0 = systemTime(timeMode);
-            _c->glGetProgramiv(program, pname, params);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.mutable_data()->assign(reinterpret_cast<const char *>(params), 1 * sizeof(GLint));
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(program);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetProgramiv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLsizei bufsize;
-        GLsizei* length;
-        GLchar* infolog;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            nsecs_t c0 = systemTime(timeMode);
-            _c->glGetProgramInfoLog(program, bufsize, length, infolog);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.mutable_data()->assign(reinterpret_cast<const char *>(infolog), strlen(infolog) * sizeof(GLchar));
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.bufsize = bufsize;
-    caller.length = length;
-    caller.infolog = infolog;
-
-    msg.set_arg0(program);
-    msg.set_arg1(bufsize);
-    msg.set_arg2(ToInt(length));
-    msg.set_arg3(ToInt(infolog));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetProgramInfoLog);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum pname;
-        GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetRenderbufferParameteriv(target, pname, params);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(target);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetRenderbufferParameteriv);
-}
-
-void Debug_glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint shader;
-        GLenum pname;
-        GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            nsecs_t c0 = systemTime(timeMode);
-            _c->glGetShaderiv(shader, pname, params);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.mutable_data()->assign(reinterpret_cast<const char *>(params), 1 * sizeof(GLint));
-            return 0;
-        }
-    } caller;
-    caller.shader = shader;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(shader);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderiv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint shader;
-        GLsizei bufsize;
-        GLsizei* length;
-        GLchar* infolog;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            nsecs_t c0 = systemTime(timeMode);
-            _c->glGetShaderInfoLog(shader, bufsize, length, infolog);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.mutable_data()->assign(reinterpret_cast<const char *>(infolog), strlen(infolog) * sizeof(GLchar));
-            return 0;
-        }
-    } caller;
-    caller.shader = shader;
-    caller.bufsize = bufsize;
-    caller.length = length;
-    caller.infolog = infolog;
-
-    msg.set_arg0(shader);
-    msg.set_arg1(bufsize);
-    msg.set_arg2(ToInt(length));
-    msg.set_arg3(ToInt(infolog));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderInfoLog);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum shadertype;
-        GLenum precisiontype;
-        GLint* range;
-        GLint* precision;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
-            return 0;
-        }
-    } caller;
-    caller.shadertype = shadertype;
-    caller.precisiontype = precisiontype;
-    caller.range = range;
-    caller.precision = precision;
-
-    msg.set_arg0(shadertype);
-    msg.set_arg1(precisiontype);
-    msg.set_arg2(ToInt(range));
-    msg.set_arg3(ToInt(precision));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderPrecisionFormat);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint shader;
-        GLsizei bufsize;
-        GLsizei* length;
-        GLchar* source;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            nsecs_t c0 = systemTime(timeMode);
-            _c->glGetShaderSource(shader, bufsize, length, source);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.mutable_data()->assign(reinterpret_cast<const char *>(source), strlen(source) * sizeof(GLchar));
-            return 0;
-        }
-    } caller;
-    caller.shader = shader;
-    caller.bufsize = bufsize;
-    caller.length = length;
-    caller.source = source;
-
-    msg.set_arg0(shader);
-    msg.set_arg1(bufsize);
-    msg.set_arg2(ToInt(length));
-    msg.set_arg3(ToInt(source));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderSource);
-}
-
-// FIXME: this function has pointers, it should be hand written
-const GLubyte* Debug_glGetString(GLenum name)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum name;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glGetString(name));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.name = name;
-
-    msg.set_arg0(name);
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetString);
-    return reinterpret_cast<const GLubyte*>(ret);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum pname;
-        GLfloat* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetTexParameterfv(target, pname, params);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(target);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetTexParameterfv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum pname;
-        GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetTexParameteriv(target, pname, params);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(target);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetTexParameteriv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetUniformfv(GLuint program, GLint location, GLfloat* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLint location;
-        GLfloat* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetUniformfv(program, location, params);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.location = location;
-    caller.params = params;
-
-    msg.set_arg0(program);
-    msg.set_arg1(location);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformfv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetUniformiv(GLuint program, GLint location, GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        GLint location;
-        GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetUniformiv(program, location, params);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-    caller.location = location;
-    caller.params = params;
-
-    msg.set_arg0(program);
-    msg.set_arg1(location);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformiv);
-}
-
-int Debug_glGetUniformLocation(GLuint program, const GLchar* name)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-        const GLchar* name;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glGetUniformLocation(program, name));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.program = program;
-    caller.name = name;
-
-    msg.set_arg0(program);
-    msg.set_arg1(ToInt(name));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformLocation);
-    return reinterpret_cast<int>(ret);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint index;
-        GLenum pname;
-        GLfloat* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetVertexAttribfv(index, pname, params);
-            return 0;
-        }
-    } caller;
-    caller.index = index;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(index);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribfv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint index;
-        GLenum pname;
-        GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetVertexAttribiv(index, pname, params);
-            return 0;
-        }
-    } caller;
-    caller.index = index;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(index);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribiv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint index;
-        GLenum pname;
-        GLvoid** pointer;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glGetVertexAttribPointerv(index, pname, pointer);
-            return 0;
-        }
-    } caller;
-    caller.index = index;
-    caller.pname = pname;
-    caller.pointer = pointer;
-
-    msg.set_arg0(index);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(pointer));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribPointerv);
-}
-
-void Debug_glHint(GLenum target, GLenum mode)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum mode;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glHint(target, mode);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.mode = mode;
-
-    msg.set_arg0(target);
-    msg.set_arg1(mode);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glHint);
-}
-
-GLboolean Debug_glIsBuffer(GLuint buffer)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint buffer;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glIsBuffer(buffer));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.buffer = buffer;
-
-    msg.set_arg0(buffer);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsBuffer);
-    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsEnabled(GLenum cap)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum cap;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glIsEnabled(cap));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.cap = cap;
-
-    msg.set_arg0(cap);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsEnabled);
-    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsFramebuffer(GLuint framebuffer)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint framebuffer;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glIsFramebuffer(framebuffer));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.framebuffer = framebuffer;
-
-    msg.set_arg0(framebuffer);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsFramebuffer);
-    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsProgram(GLuint program)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glIsProgram(program));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.program = program;
-
-    msg.set_arg0(program);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsProgram);
-    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsRenderbuffer(GLuint renderbuffer)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint renderbuffer;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glIsRenderbuffer(renderbuffer));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.renderbuffer = renderbuffer;
-
-    msg.set_arg0(renderbuffer);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsRenderbuffer);
-    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsShader(GLuint shader)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint shader;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glIsShader(shader));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.shader = shader;
-
-    msg.set_arg0(shader);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsShader);
-    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsTexture(GLuint texture)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint texture;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int * ret = reinterpret_cast<const int *>(_c->glIsTexture(texture));
-            msg.set_ret(ToInt(ret));
-            return ret;
-        }
-    } caller;
-    caller.texture = texture;
-
-    msg.set_arg0(texture);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsTexture);
-    return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-void Debug_glLineWidth(GLfloat width)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLfloat width;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glLineWidth(width);
-            return 0;
-        }
-    } caller;
-    caller.width = width;
-
-    msg.set_arg0(ToInt(width));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glLineWidth);
-}
-
-void Debug_glLinkProgram(GLuint program)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glLinkProgram(program);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-
-    msg.set_arg0(program);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glLinkProgram);
-}
-
-void Debug_glPixelStorei(GLenum pname, GLint param)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum pname;
-        GLint param;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glPixelStorei(pname, param);
-            return 0;
-        }
-    } caller;
-    caller.pname = pname;
-    caller.param = param;
-
-    msg.set_arg0(pname);
-    msg.set_arg1(param);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPixelStorei);
-}
-
-void Debug_glPolygonOffset(GLfloat factor, GLfloat units)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLfloat factor;
-        GLfloat units;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glPolygonOffset(factor, units);
-            return 0;
-        }
-    } caller;
-    caller.factor = factor;
-    caller.units = units;
-
-    msg.set_arg0(ToInt(factor));
-    msg.set_arg1(ToInt(units));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPolygonOffset);
-}
-
-void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint x;
-        GLint y;
-        GLsizei width;
-        GLsizei height;
-        GLenum format;
-        GLenum type;
-        GLvoid* pixels;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glReadPixels(x, y, width, height, format, type, pixels);
-#ifdef EXTEND_AFTER_CALL_Debug_glReadPixels
-            EXTEND_AFTER_CALL_Debug_glReadPixels;
-#endif
-            return 0;
-        }
-    } caller;
-    caller.x = x;
-    caller.y = y;
-    caller.width = width;
-    caller.height = height;
-    caller.format = format;
-    caller.type = type;
-    caller.pixels = pixels;
-
-    msg.set_arg0(x);
-    msg.set_arg1(y);
-    msg.set_arg2(width);
-    msg.set_arg3(height);
-    msg.set_arg4(format);
-    msg.set_arg5(type);
-    msg.set_arg6(ToInt(pixels));
-
-    // FIXME: check for pointer usage
-#ifdef EXTEND_Debug_glReadPixels
-    EXTEND_Debug_glReadPixels;
-#endif
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReadPixels);
-}
-
-void Debug_glReleaseShaderCompiler(void)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glReleaseShaderCompiler();
-            return 0;
-        }
-    } caller;
-
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReleaseShaderCompiler);
-}
-
-void Debug_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum internalformat;
-        GLsizei width;
-        GLsizei height;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glRenderbufferStorage(target, internalformat, width, height);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.internalformat = internalformat;
-    caller.width = width;
-    caller.height = height;
-
-    msg.set_arg0(target);
-    msg.set_arg1(internalformat);
-    msg.set_arg2(width);
-    msg.set_arg3(height);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glRenderbufferStorage);
-}
-
-void Debug_glSampleCoverage(GLclampf value, GLboolean invert)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLclampf value;
-        GLboolean invert;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glSampleCoverage(value, invert);
-            return 0;
-        }
-    } caller;
-    caller.value = value;
-    caller.invert = invert;
-
-    msg.set_arg0(ToInt(value));
-    msg.set_arg1(invert);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glSampleCoverage);
-}
-
-void Debug_glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint x;
-        GLint y;
-        GLsizei width;
-        GLsizei height;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glScissor(x, y, width, height);
-            return 0;
-        }
-    } caller;
-    caller.x = x;
-    caller.y = y;
-    caller.width = width;
-    caller.height = height;
-
-    msg.set_arg0(x);
-    msg.set_arg1(y);
-    msg.set_arg2(width);
-    msg.set_arg3(height);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glScissor);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLsizei n;
-        const GLuint* shaders;
-        GLenum binaryformat;
-        const GLvoid* binary;
-        GLsizei length;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glShaderBinary(n, shaders, binaryformat, binary, length);
-            return 0;
-        }
-    } caller;
-    caller.n = n;
-    caller.shaders = shaders;
-    caller.binaryformat = binaryformat;
-    caller.binary = binary;
-    caller.length = length;
-
-    msg.set_arg0(n);
-    msg.set_arg1(ToInt(shaders));
-    msg.set_arg2(binaryformat);
-    msg.set_arg3(ToInt(binary));
-    msg.set_arg4(length);
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderBinary);
-}
-
-void Debug_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint shader;
-        GLsizei count;
-        const GLchar** string;
-        const GLint* length;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glShaderSource(shader, count, string, length);
-#ifdef EXTEND_AFTER_CALL_Debug_glShaderSource
-            EXTEND_AFTER_CALL_Debug_glShaderSource;
-#endif
-            return 0;
-        }
-    } caller;
-    caller.shader = shader;
-    caller.count = count;
-    caller.string = string;
-    caller.length = length;
-
-    msg.set_arg0(shader);
-    msg.set_arg1(count);
-    msg.set_arg2(ToInt(string));
-    msg.set_arg3(ToInt(length));
-
-    // FIXME: check for pointer usage
-#ifdef EXTEND_Debug_glShaderSource
-    EXTEND_Debug_glShaderSource;
-#endif
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderSource);
-}
-
-void Debug_glStencilFunc(GLenum func, GLint ref, GLuint mask)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum func;
-        GLint ref;
-        GLuint mask;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glStencilFunc(func, ref, mask);
-            return 0;
-        }
-    } caller;
-    caller.func = func;
-    caller.ref = ref;
-    caller.mask = mask;
-
-    msg.set_arg0(func);
-    msg.set_arg1(ref);
-    msg.set_arg2(mask);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilFunc);
-}
-
-void Debug_glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum face;
-        GLenum func;
-        GLint ref;
-        GLuint mask;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glStencilFuncSeparate(face, func, ref, mask);
-            return 0;
-        }
-    } caller;
-    caller.face = face;
-    caller.func = func;
-    caller.ref = ref;
-    caller.mask = mask;
-
-    msg.set_arg0(face);
-    msg.set_arg1(func);
-    msg.set_arg2(ref);
-    msg.set_arg3(mask);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilFuncSeparate);
-}
-
-void Debug_glStencilMask(GLuint mask)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint mask;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glStencilMask(mask);
-            return 0;
-        }
-    } caller;
-    caller.mask = mask;
-
-    msg.set_arg0(mask);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilMask);
-}
-
-void Debug_glStencilMaskSeparate(GLenum face, GLuint mask)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum face;
-        GLuint mask;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glStencilMaskSeparate(face, mask);
-            return 0;
-        }
-    } caller;
-    caller.face = face;
-    caller.mask = mask;
-
-    msg.set_arg0(face);
-    msg.set_arg1(mask);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilMaskSeparate);
-}
-
-void Debug_glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum fail;
-        GLenum zfail;
-        GLenum zpass;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glStencilOp(fail, zfail, zpass);
-            return 0;
-        }
-    } caller;
-    caller.fail = fail;
-    caller.zfail = zfail;
-    caller.zpass = zpass;
-
-    msg.set_arg0(fail);
-    msg.set_arg1(zfail);
-    msg.set_arg2(zpass);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilOp);
-}
-
-void Debug_glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum face;
-        GLenum fail;
-        GLenum zfail;
-        GLenum zpass;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glStencilOpSeparate(face, fail, zfail, zpass);
-            return 0;
-        }
-    } caller;
-    caller.face = face;
-    caller.fail = fail;
-    caller.zfail = zfail;
-    caller.zpass = zpass;
-
-    msg.set_arg0(face);
-    msg.set_arg1(fail);
-    msg.set_arg2(zfail);
-    msg.set_arg3(zpass);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilOpSeparate);
-}
-
-void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLint level;
-        GLint internalformat;
-        GLsizei width;
-        GLsizei height;
-        GLint border;
-        GLenum format;
-        GLenum type;
-        const GLvoid* pixels;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
-#ifdef EXTEND_AFTER_CALL_Debug_glTexImage2D
-            EXTEND_AFTER_CALL_Debug_glTexImage2D;
-#endif
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.level = level;
-    caller.internalformat = internalformat;
-    caller.width = width;
-    caller.height = height;
-    caller.border = border;
-    caller.format = format;
-    caller.type = type;
-    caller.pixels = pixels;
-
-    msg.set_arg0(target);
-    msg.set_arg1(level);
-    msg.set_arg2(internalformat);
-    msg.set_arg3(width);
-    msg.set_arg4(height);
-    msg.set_arg5(border);
-    msg.set_arg6(format);
-    msg.set_arg7(type);
-    msg.set_arg8(ToInt(pixels));
-
-    // FIXME: check for pointer usage
-#ifdef EXTEND_Debug_glTexImage2D
-    EXTEND_Debug_glTexImage2D;
-#endif
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexImage2D);
-}
-
-void Debug_glTexParameterf(GLenum target, GLenum pname, GLfloat param)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum pname;
-        GLfloat param;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glTexParameterf(target, pname, param);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.pname = pname;
-    caller.param = param;
-
-    msg.set_arg0(target);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(param));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameterf);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum pname;
-        const GLfloat* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glTexParameterfv(target, pname, params);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(target);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameterfv);
-}
-
-void Debug_glTexParameteri(GLenum target, GLenum pname, GLint param)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum pname;
-        GLint param;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glTexParameteri(target, pname, param);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.pname = pname;
-    caller.param = param;
-
-    msg.set_arg0(target);
-    msg.set_arg1(pname);
-    msg.set_arg2(param);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameteri);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLenum pname;
-        const GLint* params;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glTexParameteriv(target, pname, params);
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.pname = pname;
-    caller.params = params;
-
-    msg.set_arg0(target);
-    msg.set_arg1(pname);
-    msg.set_arg2(ToInt(params));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameteriv);
-}
-
-void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLenum target;
-        GLint level;
-        GLint xoffset;
-        GLint yoffset;
-        GLsizei width;
-        GLsizei height;
-        GLenum format;
-        GLenum type;
-        const GLvoid* pixels;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
-#ifdef EXTEND_AFTER_CALL_Debug_glTexSubImage2D
-            EXTEND_AFTER_CALL_Debug_glTexSubImage2D;
-#endif
-            return 0;
-        }
-    } caller;
-    caller.target = target;
-    caller.level = level;
-    caller.xoffset = xoffset;
-    caller.yoffset = yoffset;
-    caller.width = width;
-    caller.height = height;
-    caller.format = format;
-    caller.type = type;
-    caller.pixels = pixels;
-
-    msg.set_arg0(target);
-    msg.set_arg1(level);
-    msg.set_arg2(xoffset);
-    msg.set_arg3(yoffset);
-    msg.set_arg4(width);
-    msg.set_arg5(height);
-    msg.set_arg6(format);
-    msg.set_arg7(type);
-    msg.set_arg8(ToInt(pixels));
-
-    // FIXME: check for pointer usage
-#ifdef EXTEND_Debug_glTexSubImage2D
-    EXTEND_Debug_glTexSubImage2D;
-#endif
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexSubImage2D);
-}
-
-void Debug_glUniform1f(GLint location, GLfloat x)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLfloat x;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform1f(location, x);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.x = x;
-
-    msg.set_arg0(location);
-    msg.set_arg1(ToInt(x));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1f);
-}
-
-void Debug_glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        const GLfloat* v;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform1fv(location, count, v);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.v = v;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(ToInt(v));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1fv);
-}
-
-void Debug_glUniform1i(GLint location, GLint x)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLint x;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform1i(location, x);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.x = x;
-
-    msg.set_arg0(location);
-    msg.set_arg1(x);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1i);
-}
-
-void Debug_glUniform1iv(GLint location, GLsizei count, const GLint* v)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        const GLint* v;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform1iv(location, count, v);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.v = v;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(ToInt(v));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLint));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1iv);
-}
-
-void Debug_glUniform2f(GLint location, GLfloat x, GLfloat y)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLfloat x;
-        GLfloat y;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform2f(location, x, y);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.x = x;
-    caller.y = y;
-
-    msg.set_arg0(location);
-    msg.set_arg1(ToInt(x));
-    msg.set_arg2(ToInt(y));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2f);
-}
-
-void Debug_glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        const GLfloat* v;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform2fv(location, count, v);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.v = v;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(ToInt(v));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2fv);
-}
-
-void Debug_glUniform2i(GLint location, GLint x, GLint y)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLint x;
-        GLint y;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform2i(location, x, y);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.x = x;
-    caller.y = y;
-
-    msg.set_arg0(location);
-    msg.set_arg1(x);
-    msg.set_arg2(y);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2i);
-}
-
-void Debug_glUniform2iv(GLint location, GLsizei count, const GLint* v)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        const GLint* v;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform2iv(location, count, v);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.v = v;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(ToInt(v));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLint));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2iv);
-}
-
-void Debug_glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLfloat x;
-        GLfloat y;
-        GLfloat z;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform3f(location, x, y, z);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.x = x;
-    caller.y = y;
-    caller.z = z;
-
-    msg.set_arg0(location);
-    msg.set_arg1(ToInt(x));
-    msg.set_arg2(ToInt(y));
-    msg.set_arg3(ToInt(z));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3f);
-}
-
-void Debug_glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        const GLfloat* v;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform3fv(location, count, v);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.v = v;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(ToInt(v));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3fv);
-}
-
-void Debug_glUniform3i(GLint location, GLint x, GLint y, GLint z)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLint x;
-        GLint y;
-        GLint z;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform3i(location, x, y, z);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.x = x;
-    caller.y = y;
-    caller.z = z;
-
-    msg.set_arg0(location);
-    msg.set_arg1(x);
-    msg.set_arg2(y);
-    msg.set_arg3(z);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3i);
-}
-
-void Debug_glUniform3iv(GLint location, GLsizei count, const GLint* v)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        const GLint* v;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform3iv(location, count, v);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.v = v;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(ToInt(v));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLint));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3iv);
-}
-
-void Debug_glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLfloat x;
-        GLfloat y;
-        GLfloat z;
-        GLfloat w;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform4f(location, x, y, z, w);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.x = x;
-    caller.y = y;
-    caller.z = z;
-    caller.w = w;
-
-    msg.set_arg0(location);
-    msg.set_arg1(ToInt(x));
-    msg.set_arg2(ToInt(y));
-    msg.set_arg3(ToInt(z));
-    msg.set_arg4(ToInt(w));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4f);
-}
-
-void Debug_glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        const GLfloat* v;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform4fv(location, count, v);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.v = v;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(ToInt(v));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4fv);
-}
-
-void Debug_glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLint x;
-        GLint y;
-        GLint z;
-        GLint w;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform4i(location, x, y, z, w);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.x = x;
-    caller.y = y;
-    caller.z = z;
-    caller.w = w;
-
-    msg.set_arg0(location);
-    msg.set_arg1(x);
-    msg.set_arg2(y);
-    msg.set_arg3(z);
-    msg.set_arg4(w);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4i);
-}
-
-void Debug_glUniform4iv(GLint location, GLsizei count, const GLint* v)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        const GLint* v;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniform4iv(location, count, v);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.v = v;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(ToInt(v));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLint));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4iv);
-}
-
-void Debug_glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        GLboolean transpose;
-        const GLfloat* value;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniformMatrix2fv(location, count, transpose, value);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.transpose = transpose;
-    caller.value = value;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(transpose);
-    msg.set_arg3(ToInt(value));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 4*count * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix2fv);
-}
-
-void Debug_glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        GLboolean transpose;
-        const GLfloat* value;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniformMatrix3fv(location, count, transpose, value);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.transpose = transpose;
-    caller.value = value;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(transpose);
-    msg.set_arg3(ToInt(value));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 9*count * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix3fv);
-}
-
-void Debug_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint location;
-        GLsizei count;
-        GLboolean transpose;
-        const GLfloat* value;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUniformMatrix4fv(location, count, transpose, value);
-            return 0;
-        }
-    } caller;
-    caller.location = location;
-    caller.count = count;
-    caller.transpose = transpose;
-    caller.value = value;
-
-    msg.set_arg0(location);
-    msg.set_arg1(count);
-    msg.set_arg2(transpose);
-    msg.set_arg3(ToInt(value));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 16*count * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix4fv);
-}
-
-void Debug_glUseProgram(GLuint program)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glUseProgram(program);
-            getDbgContextThreadSpecific()->glUseProgram(program);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-
-    msg.set_arg0(program);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUseProgram);
-}
-
-void Debug_glValidateProgram(GLuint program)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint program;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glValidateProgram(program);
-            return 0;
-        }
-    } caller;
-    caller.program = program;
-
-    msg.set_arg0(program);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glValidateProgram);
-}
-
-void Debug_glVertexAttrib1f(GLuint indx, GLfloat x)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint indx;
-        GLfloat x;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glVertexAttrib1f(indx, x);
-            return 0;
-        }
-    } caller;
-    caller.indx = indx;
-    caller.x = x;
-
-    msg.set_arg0(indx);
-    msg.set_arg1(ToInt(x));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib1f);
-}
-
-void Debug_glVertexAttrib1fv(GLuint indx, const GLfloat* values)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint indx;
-        const GLfloat* values;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glVertexAttrib1fv(indx, values);
-            return 0;
-        }
-    } caller;
-    caller.indx = indx;
-    caller.values = values;
-
-    msg.set_arg0(indx);
-    msg.set_arg1(ToInt(values));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 1 * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib1fv);
-}
-
-void Debug_glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint indx;
-        GLfloat x;
-        GLfloat y;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glVertexAttrib2f(indx, x, y);
-            return 0;
-        }
-    } caller;
-    caller.indx = indx;
-    caller.x = x;
-    caller.y = y;
-
-    msg.set_arg0(indx);
-    msg.set_arg1(ToInt(x));
-    msg.set_arg2(ToInt(y));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib2f);
-}
-
-void Debug_glVertexAttrib2fv(GLuint indx, const GLfloat* values)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint indx;
-        const GLfloat* values;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glVertexAttrib2fv(indx, values);
-            return 0;
-        }
-    } caller;
-    caller.indx = indx;
-    caller.values = values;
-
-    msg.set_arg0(indx);
-    msg.set_arg1(ToInt(values));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 2 * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib2fv);
-}
-
-void Debug_glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint indx;
-        GLfloat x;
-        GLfloat y;
-        GLfloat z;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glVertexAttrib3f(indx, x, y, z);
-            return 0;
-        }
-    } caller;
-    caller.indx = indx;
-    caller.x = x;
-    caller.y = y;
-    caller.z = z;
-
-    msg.set_arg0(indx);
-    msg.set_arg1(ToInt(x));
-    msg.set_arg2(ToInt(y));
-    msg.set_arg3(ToInt(z));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib3f);
-}
-
-void Debug_glVertexAttrib3fv(GLuint indx, const GLfloat* values)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint indx;
-        const GLfloat* values;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glVertexAttrib3fv(indx, values);
-            return 0;
-        }
-    } caller;
-    caller.indx = indx;
-    caller.values = values;
-
-    msg.set_arg0(indx);
-    msg.set_arg1(ToInt(values));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 3 * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib3fv);
-}
-
-void Debug_glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint indx;
-        GLfloat x;
-        GLfloat y;
-        GLfloat z;
-        GLfloat w;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glVertexAttrib4f(indx, x, y, z, w);
-            return 0;
-        }
-    } caller;
-    caller.indx = indx;
-    caller.x = x;
-    caller.y = y;
-    caller.z = z;
-    caller.w = w;
-
-    msg.set_arg0(indx);
-    msg.set_arg1(ToInt(x));
-    msg.set_arg2(ToInt(y));
-    msg.set_arg3(ToInt(z));
-    msg.set_arg4(ToInt(w));
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib4f);
-}
-
-void Debug_glVertexAttrib4fv(GLuint indx, const GLfloat* values)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint indx;
-        const GLfloat* values;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glVertexAttrib4fv(indx, values);
-            return 0;
-        }
-    } caller;
-    caller.indx = indx;
-    caller.values = values;
-
-    msg.set_arg0(indx);
-    msg.set_arg1(ToInt(values));
-
-    // FIXME: check for pointer usage
-    msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 4 * sizeof(GLfloat));
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib4fv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLuint indx;
-        GLint size;
-        GLenum type;
-        GLboolean normalized;
-        GLsizei stride;
-        const GLvoid* ptr;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
-            getDbgContextThreadSpecific()->glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
-            return 0;
-        }
-    } caller;
-    caller.indx = indx;
-    caller.size = size;
-    caller.type = type;
-    caller.normalized = normalized;
-    caller.stride = stride;
-    caller.ptr = ptr;
-
-    msg.set_arg0(indx);
-    msg.set_arg1(size);
-    msg.set_arg2(type);
-    msg.set_arg3(normalized);
-    msg.set_arg4(stride);
-    msg.set_arg5(ToInt(ptr));
-
-    // FIXME: check for pointer usage
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttribPointer);
-}
-
-void Debug_glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
-{
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        GLint x;
-        GLint y;
-        GLsizei width;
-        GLsizei height;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            _c->glViewport(x, y, width, height);
-            return 0;
-        }
-    } caller;
-    caller.x = x;
-    caller.y = y;
-    caller.width = width;
-    caller.height = height;
-
-    msg.set_arg0(x);
-    msg.set_arg1(y);
-    msg.set_arg2(width);
-    msg.set_arg3(height);
-
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glViewport);
-}
-
-// FIXME: the following functions should be written by hand
-void Debug_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
-void Debug_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
-void Debug_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
-void Debug_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
-void Debug_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
-void Debug_glGetBooleanv(GLenum pname, GLboolean* params);
-void Debug_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
-void Debug_glGetFloatv(GLenum pname, GLfloat* params);
-void Debug_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
-void Debug_glGetIntegerv(GLenum pname, GLint* params);
-void Debug_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-void Debug_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
-void Debug_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-void Debug_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
-void Debug_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
-const GLubyte* Debug_glGetString(GLenum name);
-void Debug_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params);
-void Debug_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params);
-void Debug_glGetUniformfv(GLuint program, GLint location, GLfloat* params);
-void Debug_glGetUniformiv(GLuint program, GLint location, GLint* params);
-void Debug_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params);
-void Debug_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params);
-void Debug_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer);
-void Debug_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
-void Debug_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
-void Debug_glTexParameteriv(GLenum target, GLenum pname, const GLint* params);
-void Debug_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h
deleted file mode 100644
index 0b227bc..0000000
--- a/opengl/libs/GLES2_dbg/src/api.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#define EXTEND_Debug_glCopyTexImage2D \
-    DbgContext * const dbg = getDbgContextThreadSpecific(); \
-    void * readData = dbg->GetReadPixelsBuffer(4 * width * height); \
-    /* pick easy format for client to convert */ \
-    dbg->hooks->gl.glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, readData); \
-    dbg->CompressReadPixelBuffer(msg.mutable_data()); \
-    msg.set_data_type(msg.ReferencedImage); \
-    msg.set_pixel_format(GL_RGBA); \
-    msg.set_pixel_type(GL_UNSIGNED_BYTE);
-
-#define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D
-
-#define EXTEND_AFTER_CALL_Debug_glReadPixels \
-    { \
-        DbgContext * const dbg = getDbgContextThreadSpecific(); \
-        if (dbg->IsReadPixelBuffer(pixels)) { \
-            dbg->CompressReadPixelBuffer(msg.mutable_data()); \
-            msg.set_data_type(msg.ReferencedImage); \
-        } else { \
-            const unsigned int size = width * height * GetBytesPerPixel(format, type); \
-            dbg->Compress(pixels, size, msg.mutable_data()); \
-            msg.set_data_type(msg.NonreferencedImage); \
-        } \
-    }
-
-#define EXTEND_Debug_glShaderSource \
-    std::string * const data = msg.mutable_data(); \
-    for (unsigned i = 0; i < count; i++) \
-        if (!length || length[i] < 0) \
-            data->append(string[i]); \
-        else \
-            data->append(string[i], length[i]);
-
-#define EXTEND_Debug_glTexImage2D \
-    if (pixels) { \
-        DbgContext * const dbg = getDbgContextThreadSpecific(); \
-        const unsigned size = GetBytesPerPixel(format, type) * width * height; \
-        assert(0 < size); \
-        dbg->Compress(pixels, size, msg.mutable_data()); \
-    }
-
-#define EXTEND_Debug_glTexSubImage2D EXTEND_Debug_glTexImage2D
diff --git a/opengl/libs/GLES2_dbg/src/caller.cpp b/opengl/libs/GLES2_dbg/src/caller.cpp
deleted file mode 100644
index 70d23d6..0000000
--- a/opengl/libs/GLES2_dbg/src/caller.cpp
+++ /dev/null
@@ -1,778 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-// auto generated by generate_caller_cpp.py
-// implement declarations in caller.h
-
-#include "header.h"
-
-namespace android {
-
-static const int * GenerateCall_glCompressedTexImage2D(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glCompressedTexSubImage2D(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glDrawElements(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGenBuffers(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGenFramebuffers(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGenRenderbuffers(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGenTextures(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetActiveAttrib(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetActiveUniform(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetAttachedShaders(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetBooleanv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetBufferParameteriv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetFloatv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetFramebufferAttachmentParameteriv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetIntegerv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetRenderbufferParameteriv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetShaderPrecisionFormat(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetShaderSource(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetString(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetTexParameterfv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetTexParameteriv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetUniformfv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetUniformiv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetVertexAttribfv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetVertexAttribiv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetVertexAttribPointerv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glReadPixels(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glShaderBinary(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glShaderSource(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glTexImage2D(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glTexParameterfv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glTexParameteriv(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glTexSubImage2D(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glVertexAttribPointer(DbgContext * const dbg,
-    const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-
-#include "caller.h"
-
-const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
-                  glesv2debugger::Message & msg, const int * const prevRet)
-{
-    ALOGD("GenerateCall function=%u", cmd.function());
-    const int * ret = prevRet; // only some functions have return value
-    nsecs_t c0 = systemTime(timeMode);
-    switch (cmd.function()) {    case glesv2debugger::Message_Function_glActiveTexture:
-        dbg->hooks->gl.glActiveTexture(
-            static_cast<GLenum>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glAttachShader:
-        dbg->hooks->gl.glAttachShader(
-            static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glBindAttribLocation:
-        dbg->hooks->gl.glBindAttribLocation(
-            static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()), 
-            reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glBindBuffer:
-        dbg->hooks->gl.glBindBuffer(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glBindFramebuffer:
-        dbg->hooks->gl.glBindFramebuffer(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glBindRenderbuffer:
-        dbg->hooks->gl.glBindRenderbuffer(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glBindTexture:
-        dbg->hooks->gl.glBindTexture(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glBlendColor:
-        dbg->hooks->gl.glBlendColor(
-            static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1()), 
-            static_cast<GLclampf>(cmd.arg2()), static_cast<GLclampf>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glBlendEquation:
-        dbg->hooks->gl.glBlendEquation(
-            static_cast<GLenum>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glBlendEquationSeparate:
-        dbg->hooks->gl.glBlendEquationSeparate(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glBlendFunc:
-        dbg->hooks->gl.glBlendFunc(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glBlendFuncSeparate:
-        dbg->hooks->gl.glBlendFuncSeparate(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), 
-            static_cast<GLenum>(cmd.arg2()), static_cast<GLenum>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glBufferData:
-        dbg->hooks->gl.glBufferData(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLsizeiptr>(cmd.arg1()), 
-            reinterpret_cast<GLvoid*>(const_cast<char *>(cmd.data().data())), 
-            static_cast<GLenum>(cmd.arg3()));
-        break;
-    case glesv2debugger::Message_Function_glBufferSubData:
-        dbg->hooks->gl.glBufferSubData(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLintptr>(cmd.arg1()), 
-            static_cast<GLsizeiptr>(cmd.arg2()), reinterpret_cast<GLvoid*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glCheckFramebufferStatus:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glCheckFramebufferStatus(
-            static_cast<GLenum>(cmd.arg0()))));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glClear:
-        dbg->hooks->gl.glClear(
-            static_cast<GLbitfield>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glClearColor:
-        dbg->hooks->gl.glClearColor(
-            static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1()), 
-            static_cast<GLclampf>(cmd.arg2()), static_cast<GLclampf>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glClearDepthf:
-        dbg->hooks->gl.glClearDepthf(
-            static_cast<GLclampf>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glClearStencil:
-        dbg->hooks->gl.glClearStencil(
-            static_cast<GLint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glColorMask:
-        dbg->hooks->gl.glColorMask(
-            GLboolean(cmd.arg0()), GLboolean(cmd.arg1()), GLboolean(cmd.arg2()), 
-            GLboolean(cmd.arg3()));
-        break;
-    case glesv2debugger::Message_Function_glCompileShader:
-        dbg->hooks->gl.glCompileShader(
-            static_cast<GLuint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glCompressedTexImage2D:
-        ret = GenerateCall_glCompressedTexImage2D(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glCompressedTexSubImage2D:
-        ret = GenerateCall_glCompressedTexSubImage2D(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glCopyTexImage2D:
-        dbg->hooks->gl.glCopyTexImage2D(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), 
-            static_cast<GLenum>(cmd.arg2()), static_cast<GLint>(cmd.arg3()), 
-            static_cast<GLint>(cmd.arg4()), static_cast<GLsizei>(cmd.arg5()), 
-            static_cast<GLsizei>(cmd.arg6()), static_cast<GLint>(cmd.arg7())
-            );
-        break;
-    case glesv2debugger::Message_Function_glCopyTexSubImage2D:
-        dbg->hooks->gl.glCopyTexSubImage2D(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), 
-            static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3()), 
-            static_cast<GLint>(cmd.arg4()), static_cast<GLint>(cmd.arg5()), 
-            static_cast<GLsizei>(cmd.arg6()), static_cast<GLsizei>(cmd.arg7())
-            );
-        break;
-    case glesv2debugger::Message_Function_glCreateProgram:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glCreateProgram(
-            )));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glCreateShader:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glCreateShader(
-            static_cast<GLenum>(cmd.arg0()))));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glCullFace:
-        dbg->hooks->gl.glCullFace(
-            static_cast<GLenum>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glDeleteBuffers:
-        dbg->hooks->gl.glDeleteBuffers(
-            static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glDeleteFramebuffers:
-        dbg->hooks->gl.glDeleteFramebuffers(
-            static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glDeleteProgram:
-        dbg->hooks->gl.glDeleteProgram(
-            static_cast<GLuint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glDeleteRenderbuffers:
-        dbg->hooks->gl.glDeleteRenderbuffers(
-            static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glDeleteShader:
-        dbg->hooks->gl.glDeleteShader(
-            static_cast<GLuint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glDeleteTextures:
-        dbg->hooks->gl.glDeleteTextures(
-            static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glDepthFunc:
-        dbg->hooks->gl.glDepthFunc(
-            static_cast<GLenum>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glDepthMask:
-        dbg->hooks->gl.glDepthMask(
-            GLboolean(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glDepthRangef:
-        dbg->hooks->gl.glDepthRangef(
-            static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glDetachShader:
-        dbg->hooks->gl.glDetachShader(
-            static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glDisable:
-        dbg->hooks->gl.glDisable(
-            static_cast<GLenum>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glDisableVertexAttribArray:
-        dbg->hooks->gl.glDisableVertexAttribArray(
-            static_cast<GLuint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glDrawArrays:
-        dbg->hooks->gl.glDrawArrays(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), 
-            static_cast<GLsizei>(cmd.arg2()));
-        break;
-    case glesv2debugger::Message_Function_glDrawElements:
-        ret = GenerateCall_glDrawElements(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glEnable:
-        dbg->hooks->gl.glEnable(
-            static_cast<GLenum>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glEnableVertexAttribArray:
-        dbg->hooks->gl.glEnableVertexAttribArray(
-            static_cast<GLuint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glFinish:
-        dbg->hooks->gl.glFinish(
-            );
-        break;
-    case glesv2debugger::Message_Function_glFlush:
-        dbg->hooks->gl.glFlush(
-            );
-        break;
-    case glesv2debugger::Message_Function_glFramebufferRenderbuffer:
-        dbg->hooks->gl.glFramebufferRenderbuffer(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), 
-            static_cast<GLenum>(cmd.arg2()), static_cast<GLuint>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glFramebufferTexture2D:
-        dbg->hooks->gl.glFramebufferTexture2D(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), 
-            static_cast<GLenum>(cmd.arg2()), static_cast<GLuint>(cmd.arg3()), 
-            static_cast<GLint>(cmd.arg4()));
-        break;
-    case glesv2debugger::Message_Function_glFrontFace:
-        dbg->hooks->gl.glFrontFace(
-            static_cast<GLenum>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glGenBuffers:
-        ret = GenerateCall_glGenBuffers(dbg, cmd, msg, prevRet);
-        break; // annotated output pointers
-    case glesv2debugger::Message_Function_glGenerateMipmap:
-        dbg->hooks->gl.glGenerateMipmap(
-            static_cast<GLenum>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glGenFramebuffers:
-        ret = GenerateCall_glGenFramebuffers(dbg, cmd, msg, prevRet);
-        break; // annotated output pointers
-    case glesv2debugger::Message_Function_glGenRenderbuffers:
-        ret = GenerateCall_glGenRenderbuffers(dbg, cmd, msg, prevRet);
-        break; // annotated output pointers
-    case glesv2debugger::Message_Function_glGenTextures:
-        ret = GenerateCall_glGenTextures(dbg, cmd, msg, prevRet);
-        break; // annotated output pointers
-    case glesv2debugger::Message_Function_glGetActiveAttrib:
-        ret = GenerateCall_glGetActiveAttrib(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetActiveUniform:
-        ret = GenerateCall_glGetActiveUniform(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetAttachedShaders:
-        ret = GenerateCall_glGetAttachedShaders(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetAttribLocation:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetAttribLocation(
-            static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data()))
-            )));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glGetBooleanv:
-        ret = GenerateCall_glGetBooleanv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetBufferParameteriv:
-        ret = GenerateCall_glGetBufferParameteriv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetError:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetError(
-            )));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glGetFloatv:
-        ret = GenerateCall_glGetFloatv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv:
-        ret = GenerateCall_glGetFramebufferAttachmentParameteriv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetIntegerv:
-        ret = GenerateCall_glGetIntegerv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetProgramiv:
-        ret = GenerateCall_glGetProgramiv(dbg, cmd, msg, prevRet);
-        break; // annotated output pointers
-    case glesv2debugger::Message_Function_glGetProgramInfoLog:
-        ret = GenerateCall_glGetProgramInfoLog(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetRenderbufferParameteriv:
-        ret = GenerateCall_glGetRenderbufferParameteriv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetShaderiv:
-        ret = GenerateCall_glGetShaderiv(dbg, cmd, msg, prevRet);
-        break; // annotated output pointers
-    case glesv2debugger::Message_Function_glGetShaderInfoLog:
-        ret = GenerateCall_glGetShaderInfoLog(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetShaderPrecisionFormat:
-        ret = GenerateCall_glGetShaderPrecisionFormat(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetShaderSource:
-        ret = GenerateCall_glGetShaderSource(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetString:
-        ret = GenerateCall_glGetString(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetTexParameterfv:
-        ret = GenerateCall_glGetTexParameterfv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetTexParameteriv:
-        ret = GenerateCall_glGetTexParameteriv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetUniformfv:
-        ret = GenerateCall_glGetUniformfv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetUniformiv:
-        ret = GenerateCall_glGetUniformiv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetUniformLocation:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetUniformLocation(
-            static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data()))
-            )));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glGetVertexAttribfv:
-        ret = GenerateCall_glGetVertexAttribfv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetVertexAttribiv:
-        ret = GenerateCall_glGetVertexAttribiv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glGetVertexAttribPointerv:
-        ret = GenerateCall_glGetVertexAttribPointerv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glHint:
-        dbg->hooks->gl.glHint(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glIsBuffer:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsBuffer(
-            static_cast<GLuint>(cmd.arg0()))));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glIsEnabled:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsEnabled(
-            static_cast<GLenum>(cmd.arg0()))));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glIsFramebuffer:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsFramebuffer(
-            static_cast<GLuint>(cmd.arg0()))));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glIsProgram:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsProgram(
-            static_cast<GLuint>(cmd.arg0()))));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glIsRenderbuffer:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsRenderbuffer(
-            static_cast<GLuint>(cmd.arg0()))));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glIsShader:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsShader(
-            static_cast<GLuint>(cmd.arg0()))));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glIsTexture:
-        msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsTexture(
-            static_cast<GLuint>(cmd.arg0()))));
-        if (cmd.has_ret())
-            ret = reinterpret_cast<int *>(msg.ret());
-        break;
-    case glesv2debugger::Message_Function_glLineWidth:
-        dbg->hooks->gl.glLineWidth(
-            static_cast<GLfloat>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glLinkProgram:
-        dbg->hooks->gl.glLinkProgram(
-            static_cast<GLuint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glPixelStorei:
-        dbg->hooks->gl.glPixelStorei(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glPolygonOffset:
-        dbg->hooks->gl.glPolygonOffset(
-            static_cast<GLfloat>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glReadPixels:
-        ret = GenerateCall_glReadPixels(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glReleaseShaderCompiler:
-        dbg->hooks->gl.glReleaseShaderCompiler(
-            );
-        break;
-    case glesv2debugger::Message_Function_glRenderbufferStorage:
-        dbg->hooks->gl.glRenderbufferStorage(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), 
-            static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glSampleCoverage:
-        dbg->hooks->gl.glSampleCoverage(
-            static_cast<GLclampf>(cmd.arg0()), GLboolean(cmd.arg1()));
-        break;
-    case glesv2debugger::Message_Function_glScissor:
-        dbg->hooks->gl.glScissor(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), 
-            static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glShaderBinary:
-        ret = GenerateCall_glShaderBinary(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glShaderSource:
-        ret = GenerateCall_glShaderSource(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glStencilFunc:
-        dbg->hooks->gl.glStencilFunc(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), 
-            static_cast<GLuint>(cmd.arg2()));
-        break;
-    case glesv2debugger::Message_Function_glStencilFuncSeparate:
-        dbg->hooks->gl.glStencilFuncSeparate(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), 
-            static_cast<GLint>(cmd.arg2()), static_cast<GLuint>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glStencilMask:
-        dbg->hooks->gl.glStencilMask(
-            static_cast<GLuint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glStencilMaskSeparate:
-        dbg->hooks->gl.glStencilMaskSeparate(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glStencilOp:
-        dbg->hooks->gl.glStencilOp(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), 
-            static_cast<GLenum>(cmd.arg2()));
-        break;
-    case glesv2debugger::Message_Function_glStencilOpSeparate:
-        dbg->hooks->gl.glStencilOpSeparate(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), 
-            static_cast<GLenum>(cmd.arg2()), static_cast<GLenum>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glTexImage2D:
-        ret = GenerateCall_glTexImage2D(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glTexParameterf:
-        dbg->hooks->gl.glTexParameterf(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), 
-            static_cast<GLfloat>(cmd.arg2()));
-        break;
-    case glesv2debugger::Message_Function_glTexParameterfv:
-        ret = GenerateCall_glTexParameterfv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glTexParameteri:
-        dbg->hooks->gl.glTexParameteri(
-            static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()), 
-            static_cast<GLint>(cmd.arg2()));
-        break;
-    case glesv2debugger::Message_Function_glTexParameteriv:
-        ret = GenerateCall_glTexParameteriv(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glTexSubImage2D:
-        ret = GenerateCall_glTexSubImage2D(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glUniform1f:
-        dbg->hooks->gl.glUniform1f(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform1fv:
-        dbg->hooks->gl.glUniform1fv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform1i:
-        dbg->hooks->gl.glUniform1i(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform1iv:
-        dbg->hooks->gl.glUniform1iv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform2f:
-        dbg->hooks->gl.glUniform2f(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), 
-            static_cast<GLfloat>(cmd.arg2()));
-        break;
-    case glesv2debugger::Message_Function_glUniform2fv:
-        dbg->hooks->gl.glUniform2fv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform2i:
-        dbg->hooks->gl.glUniform2i(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), 
-            static_cast<GLint>(cmd.arg2()));
-        break;
-    case glesv2debugger::Message_Function_glUniform2iv:
-        dbg->hooks->gl.glUniform2iv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform3f:
-        dbg->hooks->gl.glUniform3f(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), 
-            static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform3fv:
-        dbg->hooks->gl.glUniform3fv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform3i:
-        dbg->hooks->gl.glUniform3i(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), 
-            static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform3iv:
-        dbg->hooks->gl.glUniform3iv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform4f:
-        dbg->hooks->gl.glUniform4f(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), 
-            static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()), 
-            static_cast<GLfloat>(cmd.arg4()));
-        break;
-    case glesv2debugger::Message_Function_glUniform4fv:
-        dbg->hooks->gl.glUniform4fv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniform4i:
-        dbg->hooks->gl.glUniform4i(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), 
-            static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3()), 
-            static_cast<GLint>(cmd.arg4()));
-        break;
-    case glesv2debugger::Message_Function_glUniform4iv:
-        dbg->hooks->gl.glUniform4iv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniformMatrix2fv:
-        dbg->hooks->gl.glUniformMatrix2fv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniformMatrix3fv:
-        dbg->hooks->gl.glUniformMatrix3fv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUniformMatrix4fv:
-        dbg->hooks->gl.glUniformMatrix4fv(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()), 
-            GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glUseProgram:
-        dbg->hooks->gl.glUseProgram(
-            static_cast<GLuint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glValidateProgram:
-        dbg->hooks->gl.glValidateProgram(
-            static_cast<GLuint>(cmd.arg0()));
-        break;
-    case glesv2debugger::Message_Function_glVertexAttrib1f:
-        dbg->hooks->gl.glVertexAttrib1f(
-            static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1())
-            );
-        break;
-    case glesv2debugger::Message_Function_glVertexAttrib1fv:
-        dbg->hooks->gl.glVertexAttrib1fv(
-            static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glVertexAttrib2f:
-        dbg->hooks->gl.glVertexAttrib2f(
-            static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), 
-            static_cast<GLfloat>(cmd.arg2()));
-        break;
-    case glesv2debugger::Message_Function_glVertexAttrib2fv:
-        dbg->hooks->gl.glVertexAttrib2fv(
-            static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glVertexAttrib3f:
-        dbg->hooks->gl.glVertexAttrib3f(
-            static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), 
-            static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3())
-            );
-        break;
-    case glesv2debugger::Message_Function_glVertexAttrib3fv:
-        dbg->hooks->gl.glVertexAttrib3fv(
-            static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glVertexAttrib4f:
-        dbg->hooks->gl.glVertexAttrib4f(
-            static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()), 
-            static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()), 
-            static_cast<GLfloat>(cmd.arg4()));
-        break;
-    case glesv2debugger::Message_Function_glVertexAttrib4fv:
-        dbg->hooks->gl.glVertexAttrib4fv(
-            static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
-            );
-        break;
-    case glesv2debugger::Message_Function_glVertexAttribPointer:
-        ret = GenerateCall_glVertexAttribPointer(dbg, cmd, msg, prevRet);
-        break;
-    case glesv2debugger::Message_Function_glViewport:
-        dbg->hooks->gl.glViewport(
-            static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()), 
-            static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3())
-            );
-        break;
-    default:
-        assert(0);
-    }
-    msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-    msg.set_context_id(reinterpret_cast<int>(dbg));
-    msg.set_function(cmd.function());
-    msg.set_type(glesv2debugger::Message_Type_AfterGeneratedCall);
-    return ret;
-}
-
-}; // name space android {
diff --git a/opengl/libs/GLES2_dbg/src/caller.h b/opengl/libs/GLES2_dbg/src/caller.h
deleted file mode 100644
index e8111b3..0000000
--- a/opengl/libs/GLES2_dbg/src/caller.h
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License")
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-static const int * GenerateCall_glCompressedTexImage2D(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glCompressedTexSubImage2D(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glDrawElements(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGenBuffers(DbgContext * const dbg,
-                                       const glesv2debugger::Message & cmd,
-                                       glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGenFramebuffers(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGenRenderbuffers(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGenTextures(DbgContext * const dbg,
-                                        const glesv2debugger::Message & cmd,
-                                        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetActiveAttrib(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetActiveUniform(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetAttachedShaders(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetBooleanv(DbgContext * const dbg,
-                                        const glesv2debugger::Message & cmd,
-                                        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetBufferParameteriv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetFloatv(DbgContext * const dbg,
-                                      const glesv2debugger::Message & cmd,
-                                      glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetFramebufferAttachmentParameteriv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetIntegerv(DbgContext * const dbg,
-                                        const glesv2debugger::Message & cmd,
-                                        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    GLint params = -1;
-    dbg->hooks->gl.glGetProgramiv(cmd.arg0(), cmd.arg1(), &params);
-    msg.mutable_data()->append(reinterpret_cast<char *>(&params), sizeof(params));
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
-    GLsizei length = -1;
-    dbg->hooks->gl.glGetProgramInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
-    msg.mutable_data()->append(dbg->GetBuffer(), length);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetRenderbufferParameteriv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg,
-                                        const glesv2debugger::Message & cmd,
-                                        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    GLint params = -1;
-    dbg->hooks->gl.glGetShaderiv(cmd.arg0(), cmd.arg1(), &params);
-    msg.mutable_data()->append(reinterpret_cast<char *>(&params), sizeof(params));
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
-    GLsizei length = -1;
-    dbg->hooks->gl.glGetShaderInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
-    msg.mutable_data()->append(dbg->GetBuffer(), length);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetShaderPrecisionFormat(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetShaderSource(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetString(DbgContext * const dbg,
-                                      const glesv2debugger::Message & cmd,
-                                      glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetTexParameterfv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetTexParameteriv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetUniformfv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetUniformiv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetVertexAttribfv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetVertexAttribiv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glGetVertexAttribPointerv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glReadPixels(DbgContext * const dbg,
-                                       const glesv2debugger::Message & cmd,
-                                       glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glShaderBinary(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glShaderSource(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    const char * string = cmd.data().data();
-    dbg->hooks->gl.glShaderSource(cmd.arg0(), 1, &string, NULL);
-    return prevRet;
-}
-
-static const int * GenerateCall_glTexImage2D(DbgContext * const dbg,
-                                       const glesv2debugger::Message & cmd,
-                                       glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glTexParameterfv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glTexParameteriv(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glTexSubImage2D(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
-
-static const int * GenerateCall_glVertexAttribPointer(DbgContext * const dbg,
-        const glesv2debugger::Message & cmd,
-        glesv2debugger::Message & msg, const int * const prevRet)
-{
-    assert(0);
-    return prevRet;
-}
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
deleted file mode 100644
index 7bbaa18..0000000
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include "header.h"
-
-extern "C" {
-#include "liblzf/lzf.h"
-}
-
-namespace android {
-
-static pthread_key_t dbgEGLThreadLocalStorageKey = -1;
-static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
-
-DbgContext * getDbgContextThreadSpecific() {
-    return (DbgContext*)pthread_getspecific(dbgEGLThreadLocalStorageKey);
-}
-
-DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
-                       const unsigned MAX_VERTEX_ATTRIBS)
-        : lzf_buf(NULL), lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0)
-        , version(version), hooks(hooks)
-        , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
-        , readBytesPerPixel(4)
-        , captureSwap(0), captureDraw(0)
-        , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
-        , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
-        , program(0), maxAttrib(0)
-{
-    lzf_ref[0] = lzf_ref[1] = NULL;
-    for (unsigned i = 0; i < MAX_VERTEX_ATTRIBS; i++)
-        vertexAttribs[i] = VertexAttrib();
-    memset(&expectResponse, 0, sizeof(expectResponse));
-}
-
-DbgContext::~DbgContext()
-{
-    delete vertexAttribs;
-    free(lzf_buf);
-    free(lzf_ref[0]);
-    free(lzf_ref[1]);
-}
-
-DbgContext* CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
-{
-    pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
-    if (dbgEGLThreadLocalStorageKey == -1)
-        pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL);
-    pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
-
-    assert(version < 2);
-    assert(GL_NO_ERROR == hooks->gl.glGetError());
-    GLint MAX_VERTEX_ATTRIBS = 0;
-    hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS);
-    DbgContext* dbg = new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS);
-    glesv2debugger::Message msg, cmd;
-    msg.set_context_id(reinterpret_cast<int>(dbg));
-    msg.set_expect_response(false);
-    msg.set_type(msg.Response);
-    msg.set_function(msg.SETPROP);
-    msg.set_prop(msg.GLConstant);
-    msg.set_arg0(GL_MAX_VERTEX_ATTRIBS);
-    msg.set_arg1(MAX_VERTEX_ATTRIBS);
-    Send(msg, cmd);
-
-    GLint MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0;
-    hooks->gl.glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &MAX_COMBINED_TEXTURE_IMAGE_UNITS);
-    msg.set_arg0(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
-    msg.set_arg1(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
-    Send(msg, cmd);
-
-    pthread_setspecific(dbgEGLThreadLocalStorageKey, dbg);
-    return dbg;
-}
-
-void dbgReleaseThread() {
-    delete getDbgContextThreadSpecific();
-}
-
-unsigned GetBytesPerPixel(const GLenum format, const GLenum type)
-{
-    switch (type) {
-    case GL_UNSIGNED_SHORT_5_6_5:
-    case GL_UNSIGNED_SHORT_4_4_4_4:
-    case GL_UNSIGNED_SHORT_5_5_5_1:
-        return 2;
-    case GL_UNSIGNED_BYTE:
-        break;
-    default:
-        ALOGE("GetBytesPerPixel: unknown type %x", type);
-    }
-
-    switch (format) {
-    case GL_ALPHA:
-    case GL_LUMINANCE:
-        return 1;
-    case GL_LUMINANCE_ALPHA:
-        return 2;
-    case GL_RGB:
-        return 3;
-    case GL_RGBA:
-    case 0x80E1:   // GL_BGRA_EXT
-        return 4;
-    default:
-        ALOGE("GetBytesPerPixel: unknown format %x", format);
-    }
-
-    return 1; // in doubt...
-}
-
-void DbgContext::Fetch(const unsigned index, std::string * const data) const
-{
-    // VBO data is already on client, just send user pointer data
-    for (unsigned i = 0; i < maxAttrib; i++) {
-        if (!vertexAttribs[i].enabled)
-            continue;
-        if (vertexAttribs[i].buffer > 0)
-            continue;
-        const char * ptr = (const char *)vertexAttribs[i].ptr;
-        ptr += index * vertexAttribs[i].stride;
-        data->append(ptr, vertexAttribs[i].elemSize);
-    }
-}
-
-void DbgContext::Compress(const void * in_data, unsigned int in_len,
-                          std::string * const outStr)
-{
-    if (!lzf_buf)
-        lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
-    assert(lzf_buf);
-    const uint32_t totalDecompSize = in_len;
-    outStr->append((const char *)&totalDecompSize, sizeof(totalDecompSize));
-    for (unsigned int i = 0; i < in_len; i += LZF_CHUNK_SIZE) {
-        uint32_t chunkSize = LZF_CHUNK_SIZE;
-        if (i + LZF_CHUNK_SIZE > in_len)
-            chunkSize = in_len - i;
-        const uint32_t compSize = lzf_compress((const char *)in_data + i, chunkSize,
-                                               lzf_buf, LZF_CHUNK_SIZE);
-        outStr->append((const char *)&chunkSize, sizeof(chunkSize));
-        outStr->append((const char *)&compSize, sizeof(compSize));
-        if (compSize > 0)
-            outStr->append(lzf_buf, compSize);
-        else // compressed chunk bigger than LZF_CHUNK_SIZE (and uncompressed)
-            outStr->append((const char *)in_data + i, chunkSize);
-    }
-}
-
-unsigned char * DbgContext::Decompress(const void * in, const unsigned int inLen,
-                                       unsigned int * const outLen)
-{
-    assert(inLen > 4 * 3);
-    if (inLen < 4 * 3)
-        return NULL;
-    *outLen = *(uint32_t *)in;
-    unsigned char * const out = (unsigned char *)malloc(*outLen);
-    unsigned int outPos = 0;
-    const unsigned char * const end = (const unsigned char *)in + inLen;
-    for (const unsigned char * inData = (const unsigned char *)in + 4; inData < end; ) {
-        const uint32_t chunkOut = *(uint32_t *)inData;
-        inData += 4;
-        const uint32_t chunkIn = *(uint32_t *)inData;
-        inData += 4;
-        if (chunkIn > 0) {
-            assert(inData + chunkIn <= end);
-            assert(outPos + chunkOut <= *outLen);
-            outPos += lzf_decompress(inData, chunkIn, out + outPos, chunkOut);
-            inData += chunkIn;
-        } else {
-            assert(inData + chunkOut <= end);
-            assert(outPos + chunkOut <= *outLen);
-            memcpy(out + outPos, inData, chunkOut);
-            inData += chunkOut;
-            outPos += chunkOut;
-        }
-    }
-    return out;
-}
-
-void * DbgContext::GetReadPixelsBuffer(const unsigned size)
-{
-    if (lzf_refBufSize < size + 8) {
-        lzf_refBufSize = size + 8;
-        lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize);
-        assert(lzf_ref[0]);
-        memset(lzf_ref[0], 0, lzf_refBufSize);
-        lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize);
-        assert(lzf_ref[1]);
-        memset(lzf_ref[1], 0, lzf_refBufSize);
-    }
-    if (lzf_refSize != size) // need to clear unused ref to maintain consistency
-    { // since ref and src are swapped each time
-        memset((char *)lzf_ref[0] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize);
-        memset((char *)lzf_ref[1] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize);
-    }
-    lzf_refSize = size;
-    lzf_readIndex ^= 1;
-    return lzf_ref[lzf_readIndex];
-}
-
-void DbgContext::CompressReadPixelBuffer(std::string * const outStr)
-{
-    assert(lzf_ref[0] && lzf_ref[1]);
-    unsigned * const ref = lzf_ref[lzf_readIndex ^ 1];
-    unsigned * const src = lzf_ref[lzf_readIndex];
-    for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++)
-        ref[i] ^= src[i];
-    Compress(ref, lzf_refSize, outStr);
-}
-
-char * DbgContext::GetBuffer()
-{
-    if (!lzf_buf)
-        lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
-    assert(lzf_buf);
-    return lzf_buf;
-}
-
-unsigned int DbgContext::GetBufferSize()
-{
-    if (!lzf_buf)
-        lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
-    assert(lzf_buf);
-    if (lzf_buf)
-        return LZF_CHUNK_SIZE;
-    else
-        return 0;
-}
-
-void DbgContext::glUseProgram(GLuint program)
-{
-    while (GLenum error = hooks->gl.glGetError())
-        ALOGD("DbgContext::glUseProgram(%u): before glGetError() = 0x%.4X",
-             program, error);
-    this->program = program;
-    maxAttrib = 0;
-    if (program == 0)
-        return;
-    GLint activeAttributes = 0;
-    hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
-    maxAttrib = 0;
-    GLint maxNameLen = -1;
-    hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLen);
-    char * name = new char [maxNameLen + 1];
-    name[maxNameLen] = 0;
-    // find total number of attribute slots used
-    for (unsigned i = 0; i < activeAttributes; i++) {
-        GLint size = -1;
-        GLenum type = -1;
-        hooks->gl.glGetActiveAttrib(program, i, maxNameLen + 1, NULL, &size, &type, name);
-        GLint slot = hooks->gl.glGetAttribLocation(program, name);
-        assert(slot >= 0);
-        switch (type) {
-        case GL_FLOAT:
-        case GL_FLOAT_VEC2:
-        case GL_FLOAT_VEC3:
-        case GL_FLOAT_VEC4:
-            slot += size;
-            break;
-        case GL_FLOAT_MAT2:
-            slot += size * 2;
-            break;
-        case GL_FLOAT_MAT3:
-            slot += size * 3;
-            break;
-        case GL_FLOAT_MAT4:
-            slot += size * 4;
-            break;
-        default:
-            assert(0);
-        }
-        if (slot > maxAttrib)
-            maxAttrib = slot;
-    }
-    delete name;
-    while (GLenum error = hooks->gl.glGetError())
-        ALOGD("DbgContext::glUseProgram(%u): after glGetError() = 0x%.4X",
-             program, error);
-}
-
-static bool HasNonVBOAttribs(const DbgContext * const ctx)
-{
-    bool need = false;
-    for (unsigned i = 0; !need && i < ctx->maxAttrib; i++)
-        if (ctx->vertexAttribs[i].enabled && ctx->vertexAttribs[i].buffer == 0)
-            need = true;
-    return need;
-}
-
-void DbgContext::glVertexAttribPointer(GLuint indx, GLint size, GLenum type,
-                                       GLboolean normalized, GLsizei stride, const GLvoid* ptr)
-{
-    assert(GL_NO_ERROR == hooks->gl.glGetError());
-    assert(indx < MAX_VERTEX_ATTRIBS);
-    vertexAttribs[indx].size = size;
-    vertexAttribs[indx].type = type;
-    vertexAttribs[indx].normalized = normalized;
-    switch (type) {
-    case GL_FLOAT:
-        vertexAttribs[indx].elemSize = sizeof(GLfloat) * size;
-        break;
-    case GL_INT:
-    case GL_UNSIGNED_INT:
-        vertexAttribs[indx].elemSize = sizeof(GLint) * size;
-        break;
-    case GL_SHORT:
-    case GL_UNSIGNED_SHORT:
-        vertexAttribs[indx].elemSize = sizeof(GLshort) * size;
-        break;
-    case GL_BYTE:
-    case GL_UNSIGNED_BYTE:
-        vertexAttribs[indx].elemSize = sizeof(GLbyte) * size;
-        break;
-    default:
-        assert(0);
-    }
-    if (0 == stride)
-        stride = vertexAttribs[indx].elemSize;
-    vertexAttribs[indx].stride = stride;
-    vertexAttribs[indx].ptr = ptr;
-    hooks->gl.glGetVertexAttribiv(indx, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
-                                  (GLint *)&vertexAttribs[indx].buffer);
-    hasNonVBOAttribs = HasNonVBOAttribs(this);
-}
-
-void DbgContext::glEnableVertexAttribArray(GLuint index)
-{
-    if (index >= MAX_VERTEX_ATTRIBS)
-        return;
-    vertexAttribs[index].enabled = true;
-    hasNonVBOAttribs = HasNonVBOAttribs(this);
-}
-
-void DbgContext::glDisableVertexAttribArray(GLuint index)
-{
-    if (index >= MAX_VERTEX_ATTRIBS)
-        return;
-    vertexAttribs[index].enabled = false;
-    hasNonVBOAttribs = HasNonVBOAttribs(this);
-}
-
-void DbgContext::glBindBuffer(GLenum target, GLuint buffer)
-{
-    if (GL_ELEMENT_ARRAY_BUFFER != target)
-        return;
-    if (0 == buffer) {
-        indexBuffer = NULL;
-        return;
-    }
-    VBO * b = indexBuffers;
-    indexBuffer = NULL;
-    while (b) {
-        if (b->name == buffer) {
-            assert(GL_ELEMENT_ARRAY_BUFFER == b->target);
-            indexBuffer = b;
-            break;
-        }
-        b = b->next;
-    }
-    if (!indexBuffer)
-        indexBuffer = indexBuffers = new VBO(buffer, target, indexBuffers);
-}
-
-void DbgContext::glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
-{
-    if (GL_ELEMENT_ARRAY_BUFFER != target)
-        return;
-    assert(indexBuffer);
-    assert(size >= 0);
-    indexBuffer->size = size;
-    indexBuffer->data = realloc(indexBuffer->data, size);
-    memcpy(indexBuffer->data, data, size);
-}
-
-void DbgContext::glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
-    if (GL_ELEMENT_ARRAY_BUFFER != target)
-        return;
-    assert(indexBuffer);
-    assert(size >= 0);
-    assert(offset >= 0);
-    assert(offset + size <= indexBuffer->size);
-    memcpy((char *)indexBuffer->data + offset, data, size);
-}
-
-void DbgContext::glDeleteBuffers(GLsizei n, const GLuint *buffers)
-{
-    for (unsigned i = 0; i < n; i++) {
-        for (unsigned j = 0; j < MAX_VERTEX_ATTRIBS; j++)
-            if (buffers[i] == vertexAttribs[j].buffer) {
-                vertexAttribs[j].buffer = 0;
-                vertexAttribs[j].enabled = false;
-            }
-        VBO * b = indexBuffers, * previous = NULL;
-        while (b) {
-            if (b->name == buffers[i]) {
-                assert(GL_ELEMENT_ARRAY_BUFFER == b->target);
-                if (indexBuffer == b)
-                    indexBuffer = NULL;
-                if (previous)
-                    previous->next = b->next;
-                else
-                    indexBuffers = b->next;
-                free(b->data);
-                delete b;
-                break;
-            }
-            previous = b;
-            b = b->next;
-        }
-    }
-    hasNonVBOAttribs = HasNonVBOAttribs(this);
-}
-
-}; // namespace android
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
deleted file mode 100644
index 50f70f7..0000000
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
+++ /dev/null
@@ -1,1455 +0,0 @@
-// Generated by the protocol buffer compiler.  DO NOT EDIT!
-
-#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "debugger_message.pb.h"
-#include <google/protobuf/stubs/once.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/wire_format_lite_inl.h>
-// @@protoc_insertion_point(includes)
-
-namespace com {
-namespace android {
-namespace glesv2debugger {
-
-void protobuf_ShutdownFile_debugger_5fmessage_2eproto() {
-  delete Message::default_instance_;
-}
-
-void protobuf_AddDesc_debugger_5fmessage_2eproto() {
-  static bool already_here = false;
-  if (already_here) return;
-  already_here = true;
-  GOOGLE_PROTOBUF_VERIFY_VERSION;
-
-  Message::default_instance_ = new Message();
-  Message::default_instance_->InitAsDefaultInstance();
-  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_debugger_5fmessage_2eproto);
-}
-
-// Force AddDescriptors() to be called at static initialization time.
-struct StaticDescriptorInitializer_debugger_5fmessage_2eproto {
-  StaticDescriptorInitializer_debugger_5fmessage_2eproto() {
-    protobuf_AddDesc_debugger_5fmessage_2eproto();
-  }
-} static_descriptor_initializer_debugger_5fmessage_2eproto_;
-
-
-// ===================================================================
-
-bool Message_Function_IsValid(int value) {
-  switch(value) {
-    case 0:
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-    case 5:
-    case 6:
-    case 7:
-    case 8:
-    case 9:
-    case 10:
-    case 11:
-    case 12:
-    case 13:
-    case 14:
-    case 15:
-    case 16:
-    case 17:
-    case 18:
-    case 19:
-    case 20:
-    case 21:
-    case 22:
-    case 23:
-    case 24:
-    case 25:
-    case 26:
-    case 27:
-    case 28:
-    case 29:
-    case 30:
-    case 31:
-    case 32:
-    case 33:
-    case 34:
-    case 35:
-    case 36:
-    case 37:
-    case 38:
-    case 39:
-    case 40:
-    case 41:
-    case 42:
-    case 43:
-    case 44:
-    case 45:
-    case 46:
-    case 47:
-    case 48:
-    case 49:
-    case 50:
-    case 51:
-    case 52:
-    case 53:
-    case 54:
-    case 55:
-    case 56:
-    case 57:
-    case 58:
-    case 59:
-    case 60:
-    case 61:
-    case 62:
-    case 63:
-    case 64:
-    case 65:
-    case 66:
-    case 67:
-    case 68:
-    case 69:
-    case 70:
-    case 71:
-    case 72:
-    case 73:
-    case 74:
-    case 75:
-    case 76:
-    case 77:
-    case 78:
-    case 79:
-    case 80:
-    case 81:
-    case 82:
-    case 83:
-    case 84:
-    case 85:
-    case 86:
-    case 87:
-    case 88:
-    case 89:
-    case 90:
-    case 91:
-    case 92:
-    case 93:
-    case 94:
-    case 95:
-    case 96:
-    case 97:
-    case 98:
-    case 99:
-    case 100:
-    case 101:
-    case 102:
-    case 103:
-    case 104:
-    case 105:
-    case 106:
-    case 107:
-    case 108:
-    case 109:
-    case 110:
-    case 111:
-    case 112:
-    case 113:
-    case 114:
-    case 115:
-    case 116:
-    case 117:
-    case 118:
-    case 119:
-    case 120:
-    case 121:
-    case 122:
-    case 123:
-    case 124:
-    case 125:
-    case 126:
-    case 127:
-    case 128:
-    case 129:
-    case 130:
-    case 131:
-    case 132:
-    case 133:
-    case 134:
-    case 135:
-    case 136:
-    case 137:
-    case 138:
-    case 139:
-    case 140:
-    case 141:
-    case 142:
-    case 143:
-    case 144:
-    case 145:
-    case 146:
-    case 147:
-    case 148:
-    case 149:
-    case 150:
-    case 151:
-    case 152:
-    case 153:
-    case 154:
-    case 155:
-    case 156:
-    case 157:
-    case 158:
-    case 159:
-    case 160:
-    case 161:
-    case 162:
-    case 163:
-    case 164:
-    case 165:
-    case 166:
-    case 167:
-    case 168:
-    case 169:
-    case 170:
-    case 171:
-    case 172:
-    case 173:
-    case 174:
-    case 175:
-    case 176:
-    case 177:
-    case 178:
-    case 179:
-    case 180:
-    case 181:
-    case 182:
-    case 183:
-    case 184:
-    case 185:
-    case 186:
-    case 187:
-    case 188:
-    case 189:
-    case 190:
-      return true;
-    default:
-      return false;
-  }
-}
-
-#ifndef _MSC_VER
-const Message_Function Message::glActiveTexture;
-const Message_Function Message::glAttachShader;
-const Message_Function Message::glBindAttribLocation;
-const Message_Function Message::glBindBuffer;
-const Message_Function Message::glBindFramebuffer;
-const Message_Function Message::glBindRenderbuffer;
-const Message_Function Message::glBindTexture;
-const Message_Function Message::glBlendColor;
-const Message_Function Message::glBlendEquation;
-const Message_Function Message::glBlendEquationSeparate;
-const Message_Function Message::glBlendFunc;
-const Message_Function Message::glBlendFuncSeparate;
-const Message_Function Message::glBufferData;
-const Message_Function Message::glBufferSubData;
-const Message_Function Message::glCheckFramebufferStatus;
-const Message_Function Message::glClear;
-const Message_Function Message::glClearColor;
-const Message_Function Message::glClearDepthf;
-const Message_Function Message::glClearStencil;
-const Message_Function Message::glColorMask;
-const Message_Function Message::glCompileShader;
-const Message_Function Message::glCompressedTexImage2D;
-const Message_Function Message::glCompressedTexSubImage2D;
-const Message_Function Message::glCopyTexImage2D;
-const Message_Function Message::glCopyTexSubImage2D;
-const Message_Function Message::glCreateProgram;
-const Message_Function Message::glCreateShader;
-const Message_Function Message::glCullFace;
-const Message_Function Message::glDeleteBuffers;
-const Message_Function Message::glDeleteFramebuffers;
-const Message_Function Message::glDeleteProgram;
-const Message_Function Message::glDeleteRenderbuffers;
-const Message_Function Message::glDeleteShader;
-const Message_Function Message::glDeleteTextures;
-const Message_Function Message::glDepthFunc;
-const Message_Function Message::glDepthMask;
-const Message_Function Message::glDepthRangef;
-const Message_Function Message::glDetachShader;
-const Message_Function Message::glDisable;
-const Message_Function Message::glDisableVertexAttribArray;
-const Message_Function Message::glDrawArrays;
-const Message_Function Message::glDrawElements;
-const Message_Function Message::glEnable;
-const Message_Function Message::glEnableVertexAttribArray;
-const Message_Function Message::glFinish;
-const Message_Function Message::glFlush;
-const Message_Function Message::glFramebufferRenderbuffer;
-const Message_Function Message::glFramebufferTexture2D;
-const Message_Function Message::glFrontFace;
-const Message_Function Message::glGenBuffers;
-const Message_Function Message::glGenerateMipmap;
-const Message_Function Message::glGenFramebuffers;
-const Message_Function Message::glGenRenderbuffers;
-const Message_Function Message::glGenTextures;
-const Message_Function Message::glGetActiveAttrib;
-const Message_Function Message::glGetActiveUniform;
-const Message_Function Message::glGetAttachedShaders;
-const Message_Function Message::glGetAttribLocation;
-const Message_Function Message::glGetBooleanv;
-const Message_Function Message::glGetBufferParameteriv;
-const Message_Function Message::glGetError;
-const Message_Function Message::glGetFloatv;
-const Message_Function Message::glGetFramebufferAttachmentParameteriv;
-const Message_Function Message::glGetIntegerv;
-const Message_Function Message::glGetProgramiv;
-const Message_Function Message::glGetProgramInfoLog;
-const Message_Function Message::glGetRenderbufferParameteriv;
-const Message_Function Message::glGetShaderiv;
-const Message_Function Message::glGetShaderInfoLog;
-const Message_Function Message::glGetShaderPrecisionFormat;
-const Message_Function Message::glGetShaderSource;
-const Message_Function Message::glGetString;
-const Message_Function Message::glGetTexParameterfv;
-const Message_Function Message::glGetTexParameteriv;
-const Message_Function Message::glGetUniformfv;
-const Message_Function Message::glGetUniformiv;
-const Message_Function Message::glGetUniformLocation;
-const Message_Function Message::glGetVertexAttribfv;
-const Message_Function Message::glGetVertexAttribiv;
-const Message_Function Message::glGetVertexAttribPointerv;
-const Message_Function Message::glHint;
-const Message_Function Message::glIsBuffer;
-const Message_Function Message::glIsEnabled;
-const Message_Function Message::glIsFramebuffer;
-const Message_Function Message::glIsProgram;
-const Message_Function Message::glIsRenderbuffer;
-const Message_Function Message::glIsShader;
-const Message_Function Message::glIsTexture;
-const Message_Function Message::glLineWidth;
-const Message_Function Message::glLinkProgram;
-const Message_Function Message::glPixelStorei;
-const Message_Function Message::glPolygonOffset;
-const Message_Function Message::glReadPixels;
-const Message_Function Message::glReleaseShaderCompiler;
-const Message_Function Message::glRenderbufferStorage;
-const Message_Function Message::glSampleCoverage;
-const Message_Function Message::glScissor;
-const Message_Function Message::glShaderBinary;
-const Message_Function Message::glShaderSource;
-const Message_Function Message::glStencilFunc;
-const Message_Function Message::glStencilFuncSeparate;
-const Message_Function Message::glStencilMask;
-const Message_Function Message::glStencilMaskSeparate;
-const Message_Function Message::glStencilOp;
-const Message_Function Message::glStencilOpSeparate;
-const Message_Function Message::glTexImage2D;
-const Message_Function Message::glTexParameterf;
-const Message_Function Message::glTexParameterfv;
-const Message_Function Message::glTexParameteri;
-const Message_Function Message::glTexParameteriv;
-const Message_Function Message::glTexSubImage2D;
-const Message_Function Message::glUniform1f;
-const Message_Function Message::glUniform1fv;
-const Message_Function Message::glUniform1i;
-const Message_Function Message::glUniform1iv;
-const Message_Function Message::glUniform2f;
-const Message_Function Message::glUniform2fv;
-const Message_Function Message::glUniform2i;
-const Message_Function Message::glUniform2iv;
-const Message_Function Message::glUniform3f;
-const Message_Function Message::glUniform3fv;
-const Message_Function Message::glUniform3i;
-const Message_Function Message::glUniform3iv;
-const Message_Function Message::glUniform4f;
-const Message_Function Message::glUniform4fv;
-const Message_Function Message::glUniform4i;
-const Message_Function Message::glUniform4iv;
-const Message_Function Message::glUniformMatrix2fv;
-const Message_Function Message::glUniformMatrix3fv;
-const Message_Function Message::glUniformMatrix4fv;
-const Message_Function Message::glUseProgram;
-const Message_Function Message::glValidateProgram;
-const Message_Function Message::glVertexAttrib1f;
-const Message_Function Message::glVertexAttrib1fv;
-const Message_Function Message::glVertexAttrib2f;
-const Message_Function Message::glVertexAttrib2fv;
-const Message_Function Message::glVertexAttrib3f;
-const Message_Function Message::glVertexAttrib3fv;
-const Message_Function Message::glVertexAttrib4f;
-const Message_Function Message::glVertexAttrib4fv;
-const Message_Function Message::glVertexAttribPointer;
-const Message_Function Message::glViewport;
-const Message_Function Message::eglGetDisplay;
-const Message_Function Message::eglInitialize;
-const Message_Function Message::eglTerminate;
-const Message_Function Message::eglGetConfigs;
-const Message_Function Message::eglChooseConfig;
-const Message_Function Message::eglGetConfigAttrib;
-const Message_Function Message::eglCreateWindowSurface;
-const Message_Function Message::eglCreatePixmapSurface;
-const Message_Function Message::eglCreatePbufferSurface;
-const Message_Function Message::eglDestroySurface;
-const Message_Function Message::eglQuerySurface;
-const Message_Function Message::eglCreateContext;
-const Message_Function Message::eglDestroyContext;
-const Message_Function Message::eglMakeCurrent;
-const Message_Function Message::eglGetCurrentContext;
-const Message_Function Message::eglGetCurrentSurface;
-const Message_Function Message::eglGetCurrentDisplay;
-const Message_Function Message::eglQueryContext;
-const Message_Function Message::eglWaitGL;
-const Message_Function Message::eglWaitNative;
-const Message_Function Message::eglSwapBuffers;
-const Message_Function Message::eglCopyBuffers;
-const Message_Function Message::eglGetError;
-const Message_Function Message::eglQueryString;
-const Message_Function Message::eglGetProcAddress;
-const Message_Function Message::eglSurfaceAttrib;
-const Message_Function Message::eglBindTexImage;
-const Message_Function Message::eglReleaseTexImage;
-const Message_Function Message::eglSwapInterval;
-const Message_Function Message::eglBindAPI;
-const Message_Function Message::eglQueryAPI;
-const Message_Function Message::eglWaitClient;
-const Message_Function Message::eglReleaseThread;
-const Message_Function Message::eglCreatePbufferFromClientBuffer;
-const Message_Function Message::eglLockSurfaceKHR;
-const Message_Function Message::eglUnlockSurfaceKHR;
-const Message_Function Message::eglCreateImageKHR;
-const Message_Function Message::eglDestroyImageKHR;
-const Message_Function Message::eglCreateSyncKHR;
-const Message_Function Message::eglDestroySyncKHR;
-const Message_Function Message::eglClientWaitSyncKHR;
-const Message_Function Message::eglGetSyncAttribKHR;
-const Message_Function Message::eglSetSwapRectangleANDROID;
-const Message_Function Message::eglGetRenderBufferANDROID;
-const Message_Function Message::ACK;
-const Message_Function Message::NEG;
-const Message_Function Message::CONTINUE;
-const Message_Function Message::SKIP;
-const Message_Function Message::SETPROP;
-const Message_Function Message::Function_MIN;
-const Message_Function Message::Function_MAX;
-const int Message::Function_ARRAYSIZE;
-#endif  // _MSC_VER
-bool Message_Type_IsValid(int value) {
-  switch(value) {
-    case 0:
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      return true;
-    default:
-      return false;
-  }
-}
-
-#ifndef _MSC_VER
-const Message_Type Message::BeforeCall;
-const Message_Type Message::AfterCall;
-const Message_Type Message::AfterGeneratedCall;
-const Message_Type Message::Response;
-const Message_Type Message::CompleteCall;
-const Message_Type Message::Type_MIN;
-const Message_Type Message::Type_MAX;
-const int Message::Type_ARRAYSIZE;
-#endif  // _MSC_VER
-bool Message_DataType_IsValid(int value) {
-  switch(value) {
-    case 0:
-    case 1:
-      return true;
-    default:
-      return false;
-  }
-}
-
-#ifndef _MSC_VER
-const Message_DataType Message::ReferencedImage;
-const Message_DataType Message::NonreferencedImage;
-const Message_DataType Message::DataType_MIN;
-const Message_DataType Message::DataType_MAX;
-const int Message::DataType_ARRAYSIZE;
-#endif  // _MSC_VER
-bool Message_Prop_IsValid(int value) {
-  switch(value) {
-    case 0:
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      return true;
-    default:
-      return false;
-  }
-}
-
-#ifndef _MSC_VER
-const Message_Prop Message::CaptureDraw;
-const Message_Prop Message::TimeMode;
-const Message_Prop Message::ExpectResponse;
-const Message_Prop Message::CaptureSwap;
-const Message_Prop Message::GLConstant;
-const Message_Prop Message::Prop_MIN;
-const Message_Prop Message::Prop_MAX;
-const int Message::Prop_ARRAYSIZE;
-#endif  // _MSC_VER
-const ::std::string Message::_default_data_;
-#ifndef _MSC_VER
-const int Message::kContextIdFieldNumber;
-const int Message::kFunctionFieldNumber;
-const int Message::kTypeFieldNumber;
-const int Message::kExpectResponseFieldNumber;
-const int Message::kRetFieldNumber;
-const int Message::kArg0FieldNumber;
-const int Message::kArg1FieldNumber;
-const int Message::kArg2FieldNumber;
-const int Message::kArg3FieldNumber;
-const int Message::kArg4FieldNumber;
-const int Message::kArg5FieldNumber;
-const int Message::kArg6FieldNumber;
-const int Message::kArg7FieldNumber;
-const int Message::kArg8FieldNumber;
-const int Message::kDataFieldNumber;
-const int Message::kDataTypeFieldNumber;
-const int Message::kPixelFormatFieldNumber;
-const int Message::kPixelTypeFieldNumber;
-const int Message::kImageWidthFieldNumber;
-const int Message::kImageHeightFieldNumber;
-const int Message::kTimeFieldNumber;
-const int Message::kPropFieldNumber;
-const int Message::kClockFieldNumber;
-#endif  // !_MSC_VER
-
-Message::Message()
-  : ::google::protobuf::MessageLite() {
-  SharedCtor();
-}
-
-void Message::InitAsDefaultInstance() {
-}
-
-Message::Message(const Message& from)
-  : ::google::protobuf::MessageLite() {
-  SharedCtor();
-  MergeFrom(from);
-}
-
-void Message::SharedCtor() {
-  _cached_size_ = 0;
-  context_id_ = 0;
-  function_ = 187;
-  type_ = 0;
-  expect_response_ = false;
-  ret_ = 0;
-  arg0_ = 0;
-  arg1_ = 0;
-  arg2_ = 0;
-  arg3_ = 0;
-  arg4_ = 0;
-  arg5_ = 0;
-  arg6_ = 0;
-  arg7_ = 0;
-  arg8_ = 0;
-  data_ = const_cast< ::std::string*>(&_default_data_);
-  data_type_ = 0;
-  pixel_format_ = 0;
-  pixel_type_ = 0;
-  image_width_ = 0;
-  image_height_ = 0;
-  time_ = 0;
-  prop_ = 0;
-  clock_ = 0;
-  ::memset(_has_bits_, 0, sizeof(_has_bits_));
-}
-
-Message::~Message() {
-  SharedDtor();
-}
-
-void Message::SharedDtor() {
-  if (data_ != &_default_data_) {
-    delete data_;
-  }
-  if (this != default_instance_) {
-  }
-}
-
-void Message::SetCachedSize(int size) const {
-  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-  _cached_size_ = size;
-  GOOGLE_SAFE_CONCURRENT_WRITES_END();
-}
-const Message& Message::default_instance() {
-  if (default_instance_ == NULL) protobuf_AddDesc_debugger_5fmessage_2eproto();  return *default_instance_;
-}
-
-Message* Message::default_instance_ = NULL;
-
-Message* Message::New() const {
-  return new Message;
-}
-
-void Message::Clear() {
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    context_id_ = 0;
-    function_ = 187;
-    type_ = 0;
-    expect_response_ = false;
-    ret_ = 0;
-    arg0_ = 0;
-    arg1_ = 0;
-    arg2_ = 0;
-  }
-  if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
-    arg3_ = 0;
-    arg4_ = 0;
-    arg5_ = 0;
-    arg6_ = 0;
-    arg7_ = 0;
-    arg8_ = 0;
-    if (_has_bit(14)) {
-      if (data_ != &_default_data_) {
-        data_->clear();
-      }
-    }
-    data_type_ = 0;
-  }
-  if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
-    pixel_format_ = 0;
-    pixel_type_ = 0;
-    image_width_ = 0;
-    image_height_ = 0;
-    time_ = 0;
-    prop_ = 0;
-    clock_ = 0;
-  }
-  ::memset(_has_bits_, 0, sizeof(_has_bits_));
-}
-
-bool Message::MergePartialFromCodedStream(
-    ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
-  ::google::protobuf::uint32 tag;
-  while ((tag = input->ReadTag()) != 0) {
-    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
-      // required int32 context_id = 1;
-      case 1: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &context_id_)));
-          _set_bit(0);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(16)) goto parse_function;
-        break;
-      }
-      
-      // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
-      case 2: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_function:
-          int value;
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
-                 input, &value)));
-          if (::com::android::glesv2debugger::Message_Function_IsValid(value)) {
-            set_function(static_cast< ::com::android::glesv2debugger::Message_Function >(value));
-          }
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(24)) goto parse_type;
-        break;
-      }
-      
-      // required .com.android.glesv2debugger.Message.Type type = 3;
-      case 3: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_type:
-          int value;
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
-                 input, &value)));
-          if (::com::android::glesv2debugger::Message_Type_IsValid(value)) {
-            set_type(static_cast< ::com::android::glesv2debugger::Message_Type >(value));
-          }
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(32)) goto parse_expect_response;
-        break;
-      }
-      
-      // required bool expect_response = 4;
-      case 4: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_expect_response:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
-                 input, &expect_response_)));
-          _set_bit(3);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(40)) goto parse_ret;
-        break;
-      }
-      
-      // optional int32 ret = 5;
-      case 5: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_ret:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &ret_)));
-          _set_bit(4);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(48)) goto parse_arg0;
-        break;
-      }
-      
-      // optional int32 arg0 = 6;
-      case 6: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_arg0:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &arg0_)));
-          _set_bit(5);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(56)) goto parse_arg1;
-        break;
-      }
-      
-      // optional int32 arg1 = 7;
-      case 7: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_arg1:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &arg1_)));
-          _set_bit(6);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(64)) goto parse_arg2;
-        break;
-      }
-      
-      // optional int32 arg2 = 8;
-      case 8: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_arg2:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &arg2_)));
-          _set_bit(7);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(72)) goto parse_arg3;
-        break;
-      }
-      
-      // optional int32 arg3 = 9;
-      case 9: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_arg3:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &arg3_)));
-          _set_bit(8);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(82)) goto parse_data;
-        break;
-      }
-      
-      // optional bytes data = 10;
-      case 10: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
-         parse_data:
-          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
-                input, this->mutable_data()));
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(93)) goto parse_time;
-        break;
-      }
-      
-      // optional float time = 11;
-      case 11: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
-         parse_time:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
-                 input, &time_)));
-          _set_bit(20);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(128)) goto parse_arg4;
-        break;
-      }
-      
-      // optional int32 arg4 = 16;
-      case 16: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_arg4:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &arg4_)));
-          _set_bit(9);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(136)) goto parse_arg5;
-        break;
-      }
-      
-      // optional int32 arg5 = 17;
-      case 17: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_arg5:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &arg5_)));
-          _set_bit(10);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(144)) goto parse_arg6;
-        break;
-      }
-      
-      // optional int32 arg6 = 18;
-      case 18: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_arg6:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &arg6_)));
-          _set_bit(11);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(152)) goto parse_arg7;
-        break;
-      }
-      
-      // optional int32 arg7 = 19;
-      case 19: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_arg7:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &arg7_)));
-          _set_bit(12);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(160)) goto parse_arg8;
-        break;
-      }
-      
-      // optional int32 arg8 = 20;
-      case 20: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_arg8:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &arg8_)));
-          _set_bit(13);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(168)) goto parse_prop;
-        break;
-      }
-      
-      // optional .com.android.glesv2debugger.Message.Prop prop = 21;
-      case 21: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_prop:
-          int value;
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
-                 input, &value)));
-          if (::com::android::glesv2debugger::Message_Prop_IsValid(value)) {
-            set_prop(static_cast< ::com::android::glesv2debugger::Message_Prop >(value));
-          }
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(181)) goto parse_clock;
-        break;
-      }
-      
-      // optional float clock = 22;
-      case 22: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
-         parse_clock:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
-                 input, &clock_)));
-          _set_bit(22);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(184)) goto parse_data_type;
-        break;
-      }
-      
-      // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
-      case 23: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_data_type:
-          int value;
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
-                 input, &value)));
-          if (::com::android::glesv2debugger::Message_DataType_IsValid(value)) {
-            set_data_type(static_cast< ::com::android::glesv2debugger::Message_DataType >(value));
-          }
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(192)) goto parse_pixel_format;
-        break;
-      }
-      
-      // optional int32 pixel_format = 24;
-      case 24: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_pixel_format:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &pixel_format_)));
-          _set_bit(16);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(200)) goto parse_pixel_type;
-        break;
-      }
-      
-      // optional int32 pixel_type = 25;
-      case 25: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_pixel_type:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &pixel_type_)));
-          _set_bit(17);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(208)) goto parse_image_width;
-        break;
-      }
-      
-      // optional int32 image_width = 26;
-      case 26: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_image_width:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &image_width_)));
-          _set_bit(18);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectTag(216)) goto parse_image_height;
-        break;
-      }
-      
-      // optional int32 image_height = 27;
-      case 27: {
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
-         parse_image_height:
-          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
-                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
-                 input, &image_height_)));
-          _set_bit(19);
-        } else {
-          goto handle_uninterpreted;
-        }
-        if (input->ExpectAtEnd()) return true;
-        break;
-      }
-      
-      default: {
-      handle_uninterpreted:
-        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
-            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
-          return true;
-        }
-        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
-        break;
-      }
-    }
-  }
-  return true;
-#undef DO_
-}
-
-void Message::SerializeWithCachedSizes(
-    ::google::protobuf::io::CodedOutputStream* output) const {
-  // required int32 context_id = 1;
-  if (_has_bit(0)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->context_id(), output);
-  }
-  
-  // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
-  if (_has_bit(1)) {
-    ::google::protobuf::internal::WireFormatLite::WriteEnum(
-      2, this->function(), output);
-  }
-  
-  // required .com.android.glesv2debugger.Message.Type type = 3;
-  if (_has_bit(2)) {
-    ::google::protobuf::internal::WireFormatLite::WriteEnum(
-      3, this->type(), output);
-  }
-  
-  // required bool expect_response = 4;
-  if (_has_bit(3)) {
-    ::google::protobuf::internal::WireFormatLite::WriteBool(4, this->expect_response(), output);
-  }
-  
-  // optional int32 ret = 5;
-  if (_has_bit(4)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(5, this->ret(), output);
-  }
-  
-  // optional int32 arg0 = 6;
-  if (_has_bit(5)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(6, this->arg0(), output);
-  }
-  
-  // optional int32 arg1 = 7;
-  if (_has_bit(6)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(7, this->arg1(), output);
-  }
-  
-  // optional int32 arg2 = 8;
-  if (_has_bit(7)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(8, this->arg2(), output);
-  }
-  
-  // optional int32 arg3 = 9;
-  if (_has_bit(8)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->arg3(), output);
-  }
-  
-  // optional bytes data = 10;
-  if (_has_bit(14)) {
-    ::google::protobuf::internal::WireFormatLite::WriteBytes(
-      10, this->data(), output);
-  }
-  
-  // optional float time = 11;
-  if (_has_bit(20)) {
-    ::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output);
-  }
-  
-  // optional int32 arg4 = 16;
-  if (_has_bit(9)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(16, this->arg4(), output);
-  }
-  
-  // optional int32 arg5 = 17;
-  if (_has_bit(10)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(17, this->arg5(), output);
-  }
-  
-  // optional int32 arg6 = 18;
-  if (_has_bit(11)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(18, this->arg6(), output);
-  }
-  
-  // optional int32 arg7 = 19;
-  if (_has_bit(12)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(19, this->arg7(), output);
-  }
-  
-  // optional int32 arg8 = 20;
-  if (_has_bit(13)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(20, this->arg8(), output);
-  }
-  
-  // optional .com.android.glesv2debugger.Message.Prop prop = 21;
-  if (_has_bit(21)) {
-    ::google::protobuf::internal::WireFormatLite::WriteEnum(
-      21, this->prop(), output);
-  }
-  
-  // optional float clock = 22;
-  if (_has_bit(22)) {
-    ::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output);
-  }
-  
-  // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
-  if (_has_bit(15)) {
-    ::google::protobuf::internal::WireFormatLite::WriteEnum(
-      23, this->data_type(), output);
-  }
-  
-  // optional int32 pixel_format = 24;
-  if (_has_bit(16)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(24, this->pixel_format(), output);
-  }
-  
-  // optional int32 pixel_type = 25;
-  if (_has_bit(17)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(25, this->pixel_type(), output);
-  }
-  
-  // optional int32 image_width = 26;
-  if (_has_bit(18)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(26, this->image_width(), output);
-  }
-  
-  // optional int32 image_height = 27;
-  if (_has_bit(19)) {
-    ::google::protobuf::internal::WireFormatLite::WriteInt32(27, this->image_height(), output);
-  }
-  
-}
-
-int Message::ByteSize() const {
-  int total_size = 0;
-  
-  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    // required int32 context_id = 1;
-    if (has_context_id()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->context_id());
-    }
-    
-    // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
-    if (has_function()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::EnumSize(this->function());
-    }
-    
-    // required .com.android.glesv2debugger.Message.Type type = 3;
-    if (has_type()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
-    }
-    
-    // required bool expect_response = 4;
-    if (has_expect_response()) {
-      total_size += 1 + 1;
-    }
-    
-    // optional int32 ret = 5;
-    if (has_ret()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->ret());
-    }
-    
-    // optional int32 arg0 = 6;
-    if (has_arg0()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->arg0());
-    }
-    
-    // optional int32 arg1 = 7;
-    if (has_arg1()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->arg1());
-    }
-    
-    // optional int32 arg2 = 8;
-    if (has_arg2()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->arg2());
-    }
-    
-  }
-  if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
-    // optional int32 arg3 = 9;
-    if (has_arg3()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->arg3());
-    }
-    
-    // optional int32 arg4 = 16;
-    if (has_arg4()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->arg4());
-    }
-    
-    // optional int32 arg5 = 17;
-    if (has_arg5()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->arg5());
-    }
-    
-    // optional int32 arg6 = 18;
-    if (has_arg6()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->arg6());
-    }
-    
-    // optional int32 arg7 = 19;
-    if (has_arg7()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->arg7());
-    }
-    
-    // optional int32 arg8 = 20;
-    if (has_arg8()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->arg8());
-    }
-    
-    // optional bytes data = 10;
-    if (has_data()) {
-      total_size += 1 +
-        ::google::protobuf::internal::WireFormatLite::BytesSize(
-          this->data());
-    }
-    
-    // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
-    if (has_data_type()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::EnumSize(this->data_type());
-    }
-    
-  }
-  if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
-    // optional int32 pixel_format = 24;
-    if (has_pixel_format()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->pixel_format());
-    }
-    
-    // optional int32 pixel_type = 25;
-    if (has_pixel_type()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->pixel_type());
-    }
-    
-    // optional int32 image_width = 26;
-    if (has_image_width()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->image_width());
-    }
-    
-    // optional int32 image_height = 27;
-    if (has_image_height()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::Int32Size(
-          this->image_height());
-    }
-    
-    // optional float time = 11;
-    if (has_time()) {
-      total_size += 1 + 4;
-    }
-    
-    // optional .com.android.glesv2debugger.Message.Prop prop = 21;
-    if (has_prop()) {
-      total_size += 2 +
-        ::google::protobuf::internal::WireFormatLite::EnumSize(this->prop());
-    }
-    
-    // optional float clock = 22;
-    if (has_clock()) {
-      total_size += 2 + 4;
-    }
-    
-  }
-  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
-  _cached_size_ = total_size;
-  GOOGLE_SAFE_CONCURRENT_WRITES_END();
-  return total_size;
-}
-
-void Message::CheckTypeAndMergeFrom(
-    const ::google::protobuf::MessageLite& from) {
-  MergeFrom(*::google::protobuf::down_cast<const Message*>(&from));
-}
-
-void Message::MergeFrom(const Message& from) {
-  GOOGLE_CHECK_NE(&from, this);
-  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
-    if (from._has_bit(0)) {
-      set_context_id(from.context_id());
-    }
-    if (from._has_bit(1)) {
-      set_function(from.function());
-    }
-    if (from._has_bit(2)) {
-      set_type(from.type());
-    }
-    if (from._has_bit(3)) {
-      set_expect_response(from.expect_response());
-    }
-    if (from._has_bit(4)) {
-      set_ret(from.ret());
-    }
-    if (from._has_bit(5)) {
-      set_arg0(from.arg0());
-    }
-    if (from._has_bit(6)) {
-      set_arg1(from.arg1());
-    }
-    if (from._has_bit(7)) {
-      set_arg2(from.arg2());
-    }
-  }
-  if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
-    if (from._has_bit(8)) {
-      set_arg3(from.arg3());
-    }
-    if (from._has_bit(9)) {
-      set_arg4(from.arg4());
-    }
-    if (from._has_bit(10)) {
-      set_arg5(from.arg5());
-    }
-    if (from._has_bit(11)) {
-      set_arg6(from.arg6());
-    }
-    if (from._has_bit(12)) {
-      set_arg7(from.arg7());
-    }
-    if (from._has_bit(13)) {
-      set_arg8(from.arg8());
-    }
-    if (from._has_bit(14)) {
-      set_data(from.data());
-    }
-    if (from._has_bit(15)) {
-      set_data_type(from.data_type());
-    }
-  }
-  if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
-    if (from._has_bit(16)) {
-      set_pixel_format(from.pixel_format());
-    }
-    if (from._has_bit(17)) {
-      set_pixel_type(from.pixel_type());
-    }
-    if (from._has_bit(18)) {
-      set_image_width(from.image_width());
-    }
-    if (from._has_bit(19)) {
-      set_image_height(from.image_height());
-    }
-    if (from._has_bit(20)) {
-      set_time(from.time());
-    }
-    if (from._has_bit(21)) {
-      set_prop(from.prop());
-    }
-    if (from._has_bit(22)) {
-      set_clock(from.clock());
-    }
-  }
-}
-
-void Message::CopyFrom(const Message& from) {
-  if (&from == this) return;
-  Clear();
-  MergeFrom(from);
-}
-
-bool Message::IsInitialized() const {
-  if ((_has_bits_[0] & 0x0000000f) != 0x0000000f) return false;
-  
-  return true;
-}
-
-void Message::Swap(Message* other) {
-  if (other != this) {
-    std::swap(context_id_, other->context_id_);
-    std::swap(function_, other->function_);
-    std::swap(type_, other->type_);
-    std::swap(expect_response_, other->expect_response_);
-    std::swap(ret_, other->ret_);
-    std::swap(arg0_, other->arg0_);
-    std::swap(arg1_, other->arg1_);
-    std::swap(arg2_, other->arg2_);
-    std::swap(arg3_, other->arg3_);
-    std::swap(arg4_, other->arg4_);
-    std::swap(arg5_, other->arg5_);
-    std::swap(arg6_, other->arg6_);
-    std::swap(arg7_, other->arg7_);
-    std::swap(arg8_, other->arg8_);
-    std::swap(data_, other->data_);
-    std::swap(data_type_, other->data_type_);
-    std::swap(pixel_format_, other->pixel_format_);
-    std::swap(pixel_type_, other->pixel_type_);
-    std::swap(image_width_, other->image_width_);
-    std::swap(image_height_, other->image_height_);
-    std::swap(time_, other->time_);
-    std::swap(prop_, other->prop_);
-    std::swap(clock_, other->clock_);
-    std::swap(_has_bits_[0], other->_has_bits_[0]);
-    std::swap(_cached_size_, other->_cached_size_);
-  }
-}
-
-::std::string Message::GetTypeName() const {
-  return "com.android.glesv2debugger.Message";
-}
-
-
-// @@protoc_insertion_point(namespace_scope)
-
-}  // namespace glesv2debugger
-}  // namespace android
-}  // namespace com
-
-// @@protoc_insertion_point(global_scope)
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
deleted file mode 100644
index 5c94664..0000000
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
+++ /dev/null
@@ -1,1187 +0,0 @@
-// Generated by the protocol buffer compiler.  DO NOT EDIT!
-// source: debugger_message.proto
-
-#ifndef PROTOBUF_debugger_5fmessage_2eproto__INCLUDED
-#define PROTOBUF_debugger_5fmessage_2eproto__INCLUDED
-
-#include <string>
-
-#include <google/protobuf/stubs/common.h>
-
-#if GOOGLE_PROTOBUF_VERSION < 2003000
-#error This file was generated by a newer version of protoc which is
-#error incompatible with your Protocol Buffer headers.  Please update
-#error your headers.
-#endif
-#if 2003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
-#error This file was generated by an older version of protoc which is
-#error incompatible with your Protocol Buffer headers.  Please
-#error regenerate this file with a newer version of protoc.
-#endif
-
-#include <google/protobuf/generated_message_util.h>
-#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/extension_set.h>
-// @@protoc_insertion_point(includes)
-
-namespace com {
-namespace android {
-namespace glesv2debugger {
-
-// Internal implementation detail -- do not call these.
-void  protobuf_AddDesc_debugger_5fmessage_2eproto();
-void protobuf_AssignDesc_debugger_5fmessage_2eproto();
-void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
-
-class Message;
-
-enum Message_Function {
-  Message_Function_glActiveTexture = 0,
-  Message_Function_glAttachShader = 1,
-  Message_Function_glBindAttribLocation = 2,
-  Message_Function_glBindBuffer = 3,
-  Message_Function_glBindFramebuffer = 4,
-  Message_Function_glBindRenderbuffer = 5,
-  Message_Function_glBindTexture = 6,
-  Message_Function_glBlendColor = 7,
-  Message_Function_glBlendEquation = 8,
-  Message_Function_glBlendEquationSeparate = 9,
-  Message_Function_glBlendFunc = 10,
-  Message_Function_glBlendFuncSeparate = 11,
-  Message_Function_glBufferData = 12,
-  Message_Function_glBufferSubData = 13,
-  Message_Function_glCheckFramebufferStatus = 14,
-  Message_Function_glClear = 15,
-  Message_Function_glClearColor = 16,
-  Message_Function_glClearDepthf = 17,
-  Message_Function_glClearStencil = 18,
-  Message_Function_glColorMask = 19,
-  Message_Function_glCompileShader = 20,
-  Message_Function_glCompressedTexImage2D = 21,
-  Message_Function_glCompressedTexSubImage2D = 22,
-  Message_Function_glCopyTexImage2D = 23,
-  Message_Function_glCopyTexSubImage2D = 24,
-  Message_Function_glCreateProgram = 25,
-  Message_Function_glCreateShader = 26,
-  Message_Function_glCullFace = 27,
-  Message_Function_glDeleteBuffers = 28,
-  Message_Function_glDeleteFramebuffers = 29,
-  Message_Function_glDeleteProgram = 30,
-  Message_Function_glDeleteRenderbuffers = 31,
-  Message_Function_glDeleteShader = 32,
-  Message_Function_glDeleteTextures = 33,
-  Message_Function_glDepthFunc = 34,
-  Message_Function_glDepthMask = 35,
-  Message_Function_glDepthRangef = 36,
-  Message_Function_glDetachShader = 37,
-  Message_Function_glDisable = 38,
-  Message_Function_glDisableVertexAttribArray = 39,
-  Message_Function_glDrawArrays = 40,
-  Message_Function_glDrawElements = 41,
-  Message_Function_glEnable = 42,
-  Message_Function_glEnableVertexAttribArray = 43,
-  Message_Function_glFinish = 44,
-  Message_Function_glFlush = 45,
-  Message_Function_glFramebufferRenderbuffer = 46,
-  Message_Function_glFramebufferTexture2D = 47,
-  Message_Function_glFrontFace = 48,
-  Message_Function_glGenBuffers = 49,
-  Message_Function_glGenerateMipmap = 50,
-  Message_Function_glGenFramebuffers = 51,
-  Message_Function_glGenRenderbuffers = 52,
-  Message_Function_glGenTextures = 53,
-  Message_Function_glGetActiveAttrib = 54,
-  Message_Function_glGetActiveUniform = 55,
-  Message_Function_glGetAttachedShaders = 56,
-  Message_Function_glGetAttribLocation = 57,
-  Message_Function_glGetBooleanv = 58,
-  Message_Function_glGetBufferParameteriv = 59,
-  Message_Function_glGetError = 60,
-  Message_Function_glGetFloatv = 61,
-  Message_Function_glGetFramebufferAttachmentParameteriv = 62,
-  Message_Function_glGetIntegerv = 63,
-  Message_Function_glGetProgramiv = 64,
-  Message_Function_glGetProgramInfoLog = 65,
-  Message_Function_glGetRenderbufferParameteriv = 66,
-  Message_Function_glGetShaderiv = 67,
-  Message_Function_glGetShaderInfoLog = 68,
-  Message_Function_glGetShaderPrecisionFormat = 69,
-  Message_Function_glGetShaderSource = 70,
-  Message_Function_glGetString = 71,
-  Message_Function_glGetTexParameterfv = 72,
-  Message_Function_glGetTexParameteriv = 73,
-  Message_Function_glGetUniformfv = 74,
-  Message_Function_glGetUniformiv = 75,
-  Message_Function_glGetUniformLocation = 76,
-  Message_Function_glGetVertexAttribfv = 77,
-  Message_Function_glGetVertexAttribiv = 78,
-  Message_Function_glGetVertexAttribPointerv = 79,
-  Message_Function_glHint = 80,
-  Message_Function_glIsBuffer = 81,
-  Message_Function_glIsEnabled = 82,
-  Message_Function_glIsFramebuffer = 83,
-  Message_Function_glIsProgram = 84,
-  Message_Function_glIsRenderbuffer = 85,
-  Message_Function_glIsShader = 86,
-  Message_Function_glIsTexture = 87,
-  Message_Function_glLineWidth = 88,
-  Message_Function_glLinkProgram = 89,
-  Message_Function_glPixelStorei = 90,
-  Message_Function_glPolygonOffset = 91,
-  Message_Function_glReadPixels = 92,
-  Message_Function_glReleaseShaderCompiler = 93,
-  Message_Function_glRenderbufferStorage = 94,
-  Message_Function_glSampleCoverage = 95,
-  Message_Function_glScissor = 96,
-  Message_Function_glShaderBinary = 97,
-  Message_Function_glShaderSource = 98,
-  Message_Function_glStencilFunc = 99,
-  Message_Function_glStencilFuncSeparate = 100,
-  Message_Function_glStencilMask = 101,
-  Message_Function_glStencilMaskSeparate = 102,
-  Message_Function_glStencilOp = 103,
-  Message_Function_glStencilOpSeparate = 104,
-  Message_Function_glTexImage2D = 105,
-  Message_Function_glTexParameterf = 106,
-  Message_Function_glTexParameterfv = 107,
-  Message_Function_glTexParameteri = 108,
-  Message_Function_glTexParameteriv = 109,
-  Message_Function_glTexSubImage2D = 110,
-  Message_Function_glUniform1f = 111,
-  Message_Function_glUniform1fv = 112,
-  Message_Function_glUniform1i = 113,
-  Message_Function_glUniform1iv = 114,
-  Message_Function_glUniform2f = 115,
-  Message_Function_glUniform2fv = 116,
-  Message_Function_glUniform2i = 117,
-  Message_Function_glUniform2iv = 118,
-  Message_Function_glUniform3f = 119,
-  Message_Function_glUniform3fv = 120,
-  Message_Function_glUniform3i = 121,
-  Message_Function_glUniform3iv = 122,
-  Message_Function_glUniform4f = 123,
-  Message_Function_glUniform4fv = 124,
-  Message_Function_glUniform4i = 125,
-  Message_Function_glUniform4iv = 126,
-  Message_Function_glUniformMatrix2fv = 127,
-  Message_Function_glUniformMatrix3fv = 128,
-  Message_Function_glUniformMatrix4fv = 129,
-  Message_Function_glUseProgram = 130,
-  Message_Function_glValidateProgram = 131,
-  Message_Function_glVertexAttrib1f = 132,
-  Message_Function_glVertexAttrib1fv = 133,
-  Message_Function_glVertexAttrib2f = 134,
-  Message_Function_glVertexAttrib2fv = 135,
-  Message_Function_glVertexAttrib3f = 136,
-  Message_Function_glVertexAttrib3fv = 137,
-  Message_Function_glVertexAttrib4f = 138,
-  Message_Function_glVertexAttrib4fv = 139,
-  Message_Function_glVertexAttribPointer = 140,
-  Message_Function_glViewport = 141,
-  Message_Function_eglGetDisplay = 142,
-  Message_Function_eglInitialize = 143,
-  Message_Function_eglTerminate = 144,
-  Message_Function_eglGetConfigs = 145,
-  Message_Function_eglChooseConfig = 146,
-  Message_Function_eglGetConfigAttrib = 147,
-  Message_Function_eglCreateWindowSurface = 148,
-  Message_Function_eglCreatePixmapSurface = 149,
-  Message_Function_eglCreatePbufferSurface = 150,
-  Message_Function_eglDestroySurface = 151,
-  Message_Function_eglQuerySurface = 152,
-  Message_Function_eglCreateContext = 153,
-  Message_Function_eglDestroyContext = 154,
-  Message_Function_eglMakeCurrent = 155,
-  Message_Function_eglGetCurrentContext = 156,
-  Message_Function_eglGetCurrentSurface = 157,
-  Message_Function_eglGetCurrentDisplay = 158,
-  Message_Function_eglQueryContext = 159,
-  Message_Function_eglWaitGL = 160,
-  Message_Function_eglWaitNative = 161,
-  Message_Function_eglSwapBuffers = 162,
-  Message_Function_eglCopyBuffers = 163,
-  Message_Function_eglGetError = 164,
-  Message_Function_eglQueryString = 165,
-  Message_Function_eglGetProcAddress = 166,
-  Message_Function_eglSurfaceAttrib = 167,
-  Message_Function_eglBindTexImage = 168,
-  Message_Function_eglReleaseTexImage = 169,
-  Message_Function_eglSwapInterval = 170,
-  Message_Function_eglBindAPI = 171,
-  Message_Function_eglQueryAPI = 172,
-  Message_Function_eglWaitClient = 173,
-  Message_Function_eglReleaseThread = 174,
-  Message_Function_eglCreatePbufferFromClientBuffer = 175,
-  Message_Function_eglLockSurfaceKHR = 176,
-  Message_Function_eglUnlockSurfaceKHR = 177,
-  Message_Function_eglCreateImageKHR = 178,
-  Message_Function_eglDestroyImageKHR = 179,
-  Message_Function_eglCreateSyncKHR = 180,
-  Message_Function_eglDestroySyncKHR = 181,
-  Message_Function_eglClientWaitSyncKHR = 182,
-  Message_Function_eglGetSyncAttribKHR = 183,
-  Message_Function_eglSetSwapRectangleANDROID = 184,
-  Message_Function_eglGetRenderBufferANDROID = 185,
-  Message_Function_ACK = 186,
-  Message_Function_NEG = 187,
-  Message_Function_CONTINUE = 188,
-  Message_Function_SKIP = 189,
-  Message_Function_SETPROP = 190
-};
-bool Message_Function_IsValid(int value);
-const Message_Function Message_Function_Function_MIN = Message_Function_glActiveTexture;
-const Message_Function Message_Function_Function_MAX = Message_Function_SETPROP;
-const int Message_Function_Function_ARRAYSIZE = Message_Function_Function_MAX + 1;
-
-enum Message_Type {
-  Message_Type_BeforeCall = 0,
-  Message_Type_AfterCall = 1,
-  Message_Type_AfterGeneratedCall = 2,
-  Message_Type_Response = 3,
-  Message_Type_CompleteCall = 4
-};
-bool Message_Type_IsValid(int value);
-const Message_Type Message_Type_Type_MIN = Message_Type_BeforeCall;
-const Message_Type Message_Type_Type_MAX = Message_Type_CompleteCall;
-const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1;
-
-enum Message_DataType {
-  Message_DataType_ReferencedImage = 0,
-  Message_DataType_NonreferencedImage = 1
-};
-bool Message_DataType_IsValid(int value);
-const Message_DataType Message_DataType_DataType_MIN = Message_DataType_ReferencedImage;
-const Message_DataType Message_DataType_DataType_MAX = Message_DataType_NonreferencedImage;
-const int Message_DataType_DataType_ARRAYSIZE = Message_DataType_DataType_MAX + 1;
-
-enum Message_Prop {
-  Message_Prop_CaptureDraw = 0,
-  Message_Prop_TimeMode = 1,
-  Message_Prop_ExpectResponse = 2,
-  Message_Prop_CaptureSwap = 3,
-  Message_Prop_GLConstant = 4
-};
-bool Message_Prop_IsValid(int value);
-const Message_Prop Message_Prop_Prop_MIN = Message_Prop_CaptureDraw;
-const Message_Prop Message_Prop_Prop_MAX = Message_Prop_GLConstant;
-const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1;
-
-// ===================================================================
-
-class Message : public ::google::protobuf::MessageLite {
- public:
-  Message();
-  virtual ~Message();
-  
-  Message(const Message& from);
-  
-  inline Message& operator=(const Message& from) {
-    CopyFrom(from);
-    return *this;
-  }
-  
-  static const Message& default_instance();
-  
-  void Swap(Message* other);
-  
-  // implements Message ----------------------------------------------
-  
-  Message* New() const;
-  void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
-  void CopyFrom(const Message& from);
-  void MergeFrom(const Message& from);
-  void Clear();
-  bool IsInitialized() const;
-  
-  int ByteSize() const;
-  bool MergePartialFromCodedStream(
-      ::google::protobuf::io::CodedInputStream* input);
-  void SerializeWithCachedSizes(
-      ::google::protobuf::io::CodedOutputStream* output) const;
-  int GetCachedSize() const { return _cached_size_; }
-  private:
-  void SharedCtor();
-  void SharedDtor();
-  void SetCachedSize(int size) const;
-  public:
-  
-  ::std::string GetTypeName() const;
-  
-  // nested types ----------------------------------------------------
-  
-  typedef Message_Function Function;
-  static const Function glActiveTexture = Message_Function_glActiveTexture;
-  static const Function glAttachShader = Message_Function_glAttachShader;
-  static const Function glBindAttribLocation = Message_Function_glBindAttribLocation;
-  static const Function glBindBuffer = Message_Function_glBindBuffer;
-  static const Function glBindFramebuffer = Message_Function_glBindFramebuffer;
-  static const Function glBindRenderbuffer = Message_Function_glBindRenderbuffer;
-  static const Function glBindTexture = Message_Function_glBindTexture;
-  static const Function glBlendColor = Message_Function_glBlendColor;
-  static const Function glBlendEquation = Message_Function_glBlendEquation;
-  static const Function glBlendEquationSeparate = Message_Function_glBlendEquationSeparate;
-  static const Function glBlendFunc = Message_Function_glBlendFunc;
-  static const Function glBlendFuncSeparate = Message_Function_glBlendFuncSeparate;
-  static const Function glBufferData = Message_Function_glBufferData;
-  static const Function glBufferSubData = Message_Function_glBufferSubData;
-  static const Function glCheckFramebufferStatus = Message_Function_glCheckFramebufferStatus;
-  static const Function glClear = Message_Function_glClear;
-  static const Function glClearColor = Message_Function_glClearColor;
-  static const Function glClearDepthf = Message_Function_glClearDepthf;
-  static const Function glClearStencil = Message_Function_glClearStencil;
-  static const Function glColorMask = Message_Function_glColorMask;
-  static const Function glCompileShader = Message_Function_glCompileShader;
-  static const Function glCompressedTexImage2D = Message_Function_glCompressedTexImage2D;
-  static const Function glCompressedTexSubImage2D = Message_Function_glCompressedTexSubImage2D;
-  static const Function glCopyTexImage2D = Message_Function_glCopyTexImage2D;
-  static const Function glCopyTexSubImage2D = Message_Function_glCopyTexSubImage2D;
-  static const Function glCreateProgram = Message_Function_glCreateProgram;
-  static const Function glCreateShader = Message_Function_glCreateShader;
-  static const Function glCullFace = Message_Function_glCullFace;
-  static const Function glDeleteBuffers = Message_Function_glDeleteBuffers;
-  static const Function glDeleteFramebuffers = Message_Function_glDeleteFramebuffers;
-  static const Function glDeleteProgram = Message_Function_glDeleteProgram;
-  static const Function glDeleteRenderbuffers = Message_Function_glDeleteRenderbuffers;
-  static const Function glDeleteShader = Message_Function_glDeleteShader;
-  static const Function glDeleteTextures = Message_Function_glDeleteTextures;
-  static const Function glDepthFunc = Message_Function_glDepthFunc;
-  static const Function glDepthMask = Message_Function_glDepthMask;
-  static const Function glDepthRangef = Message_Function_glDepthRangef;
-  static const Function glDetachShader = Message_Function_glDetachShader;
-  static const Function glDisable = Message_Function_glDisable;
-  static const Function glDisableVertexAttribArray = Message_Function_glDisableVertexAttribArray;
-  static const Function glDrawArrays = Message_Function_glDrawArrays;
-  static const Function glDrawElements = Message_Function_glDrawElements;
-  static const Function glEnable = Message_Function_glEnable;
-  static const Function glEnableVertexAttribArray = Message_Function_glEnableVertexAttribArray;
-  static const Function glFinish = Message_Function_glFinish;
-  static const Function glFlush = Message_Function_glFlush;
-  static const Function glFramebufferRenderbuffer = Message_Function_glFramebufferRenderbuffer;
-  static const Function glFramebufferTexture2D = Message_Function_glFramebufferTexture2D;
-  static const Function glFrontFace = Message_Function_glFrontFace;
-  static const Function glGenBuffers = Message_Function_glGenBuffers;
-  static const Function glGenerateMipmap = Message_Function_glGenerateMipmap;
-  static const Function glGenFramebuffers = Message_Function_glGenFramebuffers;
-  static const Function glGenRenderbuffers = Message_Function_glGenRenderbuffers;
-  static const Function glGenTextures = Message_Function_glGenTextures;
-  static const Function glGetActiveAttrib = Message_Function_glGetActiveAttrib;
-  static const Function glGetActiveUniform = Message_Function_glGetActiveUniform;
-  static const Function glGetAttachedShaders = Message_Function_glGetAttachedShaders;
-  static const Function glGetAttribLocation = Message_Function_glGetAttribLocation;
-  static const Function glGetBooleanv = Message_Function_glGetBooleanv;
-  static const Function glGetBufferParameteriv = Message_Function_glGetBufferParameteriv;
-  static const Function glGetError = Message_Function_glGetError;
-  static const Function glGetFloatv = Message_Function_glGetFloatv;
-  static const Function glGetFramebufferAttachmentParameteriv = Message_Function_glGetFramebufferAttachmentParameteriv;
-  static const Function glGetIntegerv = Message_Function_glGetIntegerv;
-  static const Function glGetProgramiv = Message_Function_glGetProgramiv;
-  static const Function glGetProgramInfoLog = Message_Function_glGetProgramInfoLog;
-  static const Function glGetRenderbufferParameteriv = Message_Function_glGetRenderbufferParameteriv;
-  static const Function glGetShaderiv = Message_Function_glGetShaderiv;
-  static const Function glGetShaderInfoLog = Message_Function_glGetShaderInfoLog;
-  static const Function glGetShaderPrecisionFormat = Message_Function_glGetShaderPrecisionFormat;
-  static const Function glGetShaderSource = Message_Function_glGetShaderSource;
-  static const Function glGetString = Message_Function_glGetString;
-  static const Function glGetTexParameterfv = Message_Function_glGetTexParameterfv;
-  static const Function glGetTexParameteriv = Message_Function_glGetTexParameteriv;
-  static const Function glGetUniformfv = Message_Function_glGetUniformfv;
-  static const Function glGetUniformiv = Message_Function_glGetUniformiv;
-  static const Function glGetUniformLocation = Message_Function_glGetUniformLocation;
-  static const Function glGetVertexAttribfv = Message_Function_glGetVertexAttribfv;
-  static const Function glGetVertexAttribiv = Message_Function_glGetVertexAttribiv;
-  static const Function glGetVertexAttribPointerv = Message_Function_glGetVertexAttribPointerv;
-  static const Function glHint = Message_Function_glHint;
-  static const Function glIsBuffer = Message_Function_glIsBuffer;
-  static const Function glIsEnabled = Message_Function_glIsEnabled;
-  static const Function glIsFramebuffer = Message_Function_glIsFramebuffer;
-  static const Function glIsProgram = Message_Function_glIsProgram;
-  static const Function glIsRenderbuffer = Message_Function_glIsRenderbuffer;
-  static const Function glIsShader = Message_Function_glIsShader;
-  static const Function glIsTexture = Message_Function_glIsTexture;
-  static const Function glLineWidth = Message_Function_glLineWidth;
-  static const Function glLinkProgram = Message_Function_glLinkProgram;
-  static const Function glPixelStorei = Message_Function_glPixelStorei;
-  static const Function glPolygonOffset = Message_Function_glPolygonOffset;
-  static const Function glReadPixels = Message_Function_glReadPixels;
-  static const Function glReleaseShaderCompiler = Message_Function_glReleaseShaderCompiler;
-  static const Function glRenderbufferStorage = Message_Function_glRenderbufferStorage;
-  static const Function glSampleCoverage = Message_Function_glSampleCoverage;
-  static const Function glScissor = Message_Function_glScissor;
-  static const Function glShaderBinary = Message_Function_glShaderBinary;
-  static const Function glShaderSource = Message_Function_glShaderSource;
-  static const Function glStencilFunc = Message_Function_glStencilFunc;
-  static const Function glStencilFuncSeparate = Message_Function_glStencilFuncSeparate;
-  static const Function glStencilMask = Message_Function_glStencilMask;
-  static const Function glStencilMaskSeparate = Message_Function_glStencilMaskSeparate;
-  static const Function glStencilOp = Message_Function_glStencilOp;
-  static const Function glStencilOpSeparate = Message_Function_glStencilOpSeparate;
-  static const Function glTexImage2D = Message_Function_glTexImage2D;
-  static const Function glTexParameterf = Message_Function_glTexParameterf;
-  static const Function glTexParameterfv = Message_Function_glTexParameterfv;
-  static const Function glTexParameteri = Message_Function_glTexParameteri;
-  static const Function glTexParameteriv = Message_Function_glTexParameteriv;
-  static const Function glTexSubImage2D = Message_Function_glTexSubImage2D;
-  static const Function glUniform1f = Message_Function_glUniform1f;
-  static const Function glUniform1fv = Message_Function_glUniform1fv;
-  static const Function glUniform1i = Message_Function_glUniform1i;
-  static const Function glUniform1iv = Message_Function_glUniform1iv;
-  static const Function glUniform2f = Message_Function_glUniform2f;
-  static const Function glUniform2fv = Message_Function_glUniform2fv;
-  static const Function glUniform2i = Message_Function_glUniform2i;
-  static const Function glUniform2iv = Message_Function_glUniform2iv;
-  static const Function glUniform3f = Message_Function_glUniform3f;
-  static const Function glUniform3fv = Message_Function_glUniform3fv;
-  static const Function glUniform3i = Message_Function_glUniform3i;
-  static const Function glUniform3iv = Message_Function_glUniform3iv;
-  static const Function glUniform4f = Message_Function_glUniform4f;
-  static const Function glUniform4fv = Message_Function_glUniform4fv;
-  static const Function glUniform4i = Message_Function_glUniform4i;
-  static const Function glUniform4iv = Message_Function_glUniform4iv;
-  static const Function glUniformMatrix2fv = Message_Function_glUniformMatrix2fv;
-  static const Function glUniformMatrix3fv = Message_Function_glUniformMatrix3fv;
-  static const Function glUniformMatrix4fv = Message_Function_glUniformMatrix4fv;
-  static const Function glUseProgram = Message_Function_glUseProgram;
-  static const Function glValidateProgram = Message_Function_glValidateProgram;
-  static const Function glVertexAttrib1f = Message_Function_glVertexAttrib1f;
-  static const Function glVertexAttrib1fv = Message_Function_glVertexAttrib1fv;
-  static const Function glVertexAttrib2f = Message_Function_glVertexAttrib2f;
-  static const Function glVertexAttrib2fv = Message_Function_glVertexAttrib2fv;
-  static const Function glVertexAttrib3f = Message_Function_glVertexAttrib3f;
-  static const Function glVertexAttrib3fv = Message_Function_glVertexAttrib3fv;
-  static const Function glVertexAttrib4f = Message_Function_glVertexAttrib4f;
-  static const Function glVertexAttrib4fv = Message_Function_glVertexAttrib4fv;
-  static const Function glVertexAttribPointer = Message_Function_glVertexAttribPointer;
-  static const Function glViewport = Message_Function_glViewport;
-  static const Function eglGetDisplay = Message_Function_eglGetDisplay;
-  static const Function eglInitialize = Message_Function_eglInitialize;
-  static const Function eglTerminate = Message_Function_eglTerminate;
-  static const Function eglGetConfigs = Message_Function_eglGetConfigs;
-  static const Function eglChooseConfig = Message_Function_eglChooseConfig;
-  static const Function eglGetConfigAttrib = Message_Function_eglGetConfigAttrib;
-  static const Function eglCreateWindowSurface = Message_Function_eglCreateWindowSurface;
-  static const Function eglCreatePixmapSurface = Message_Function_eglCreatePixmapSurface;
-  static const Function eglCreatePbufferSurface = Message_Function_eglCreatePbufferSurface;
-  static const Function eglDestroySurface = Message_Function_eglDestroySurface;
-  static const Function eglQuerySurface = Message_Function_eglQuerySurface;
-  static const Function eglCreateContext = Message_Function_eglCreateContext;
-  static const Function eglDestroyContext = Message_Function_eglDestroyContext;
-  static const Function eglMakeCurrent = Message_Function_eglMakeCurrent;
-  static const Function eglGetCurrentContext = Message_Function_eglGetCurrentContext;
-  static const Function eglGetCurrentSurface = Message_Function_eglGetCurrentSurface;
-  static const Function eglGetCurrentDisplay = Message_Function_eglGetCurrentDisplay;
-  static const Function eglQueryContext = Message_Function_eglQueryContext;
-  static const Function eglWaitGL = Message_Function_eglWaitGL;
-  static const Function eglWaitNative = Message_Function_eglWaitNative;
-  static const Function eglSwapBuffers = Message_Function_eglSwapBuffers;
-  static const Function eglCopyBuffers = Message_Function_eglCopyBuffers;
-  static const Function eglGetError = Message_Function_eglGetError;
-  static const Function eglQueryString = Message_Function_eglQueryString;
-  static const Function eglGetProcAddress = Message_Function_eglGetProcAddress;
-  static const Function eglSurfaceAttrib = Message_Function_eglSurfaceAttrib;
-  static const Function eglBindTexImage = Message_Function_eglBindTexImage;
-  static const Function eglReleaseTexImage = Message_Function_eglReleaseTexImage;
-  static const Function eglSwapInterval = Message_Function_eglSwapInterval;
-  static const Function eglBindAPI = Message_Function_eglBindAPI;
-  static const Function eglQueryAPI = Message_Function_eglQueryAPI;
-  static const Function eglWaitClient = Message_Function_eglWaitClient;
-  static const Function eglReleaseThread = Message_Function_eglReleaseThread;
-  static const Function eglCreatePbufferFromClientBuffer = Message_Function_eglCreatePbufferFromClientBuffer;
-  static const Function eglLockSurfaceKHR = Message_Function_eglLockSurfaceKHR;
-  static const Function eglUnlockSurfaceKHR = Message_Function_eglUnlockSurfaceKHR;
-  static const Function eglCreateImageKHR = Message_Function_eglCreateImageKHR;
-  static const Function eglDestroyImageKHR = Message_Function_eglDestroyImageKHR;
-  static const Function eglCreateSyncKHR = Message_Function_eglCreateSyncKHR;
-  static const Function eglDestroySyncKHR = Message_Function_eglDestroySyncKHR;
-  static const Function eglClientWaitSyncKHR = Message_Function_eglClientWaitSyncKHR;
-  static const Function eglGetSyncAttribKHR = Message_Function_eglGetSyncAttribKHR;
-  static const Function eglSetSwapRectangleANDROID = Message_Function_eglSetSwapRectangleANDROID;
-  static const Function eglGetRenderBufferANDROID = Message_Function_eglGetRenderBufferANDROID;
-  static const Function ACK = Message_Function_ACK;
-  static const Function NEG = Message_Function_NEG;
-  static const Function CONTINUE = Message_Function_CONTINUE;
-  static const Function SKIP = Message_Function_SKIP;
-  static const Function SETPROP = Message_Function_SETPROP;
-  static inline bool Function_IsValid(int value) {
-    return Message_Function_IsValid(value);
-  }
-  static const Function Function_MIN =
-    Message_Function_Function_MIN;
-  static const Function Function_MAX =
-    Message_Function_Function_MAX;
-  static const int Function_ARRAYSIZE =
-    Message_Function_Function_ARRAYSIZE;
-  
-  typedef Message_Type Type;
-  static const Type BeforeCall = Message_Type_BeforeCall;
-  static const Type AfterCall = Message_Type_AfterCall;
-  static const Type AfterGeneratedCall = Message_Type_AfterGeneratedCall;
-  static const Type Response = Message_Type_Response;
-  static const Type CompleteCall = Message_Type_CompleteCall;
-  static inline bool Type_IsValid(int value) {
-    return Message_Type_IsValid(value);
-  }
-  static const Type Type_MIN =
-    Message_Type_Type_MIN;
-  static const Type Type_MAX =
-    Message_Type_Type_MAX;
-  static const int Type_ARRAYSIZE =
-    Message_Type_Type_ARRAYSIZE;
-  
-  typedef Message_DataType DataType;
-  static const DataType ReferencedImage = Message_DataType_ReferencedImage;
-  static const DataType NonreferencedImage = Message_DataType_NonreferencedImage;
-  static inline bool DataType_IsValid(int value) {
-    return Message_DataType_IsValid(value);
-  }
-  static const DataType DataType_MIN =
-    Message_DataType_DataType_MIN;
-  static const DataType DataType_MAX =
-    Message_DataType_DataType_MAX;
-  static const int DataType_ARRAYSIZE =
-    Message_DataType_DataType_ARRAYSIZE;
-  
-  typedef Message_Prop Prop;
-  static const Prop CaptureDraw = Message_Prop_CaptureDraw;
-  static const Prop TimeMode = Message_Prop_TimeMode;
-  static const Prop ExpectResponse = Message_Prop_ExpectResponse;
-  static const Prop CaptureSwap = Message_Prop_CaptureSwap;
-  static const Prop GLConstant = Message_Prop_GLConstant;
-  static inline bool Prop_IsValid(int value) {
-    return Message_Prop_IsValid(value);
-  }
-  static const Prop Prop_MIN =
-    Message_Prop_Prop_MIN;
-  static const Prop Prop_MAX =
-    Message_Prop_Prop_MAX;
-  static const int Prop_ARRAYSIZE =
-    Message_Prop_Prop_ARRAYSIZE;
-  
-  // accessors -------------------------------------------------------
-  
-  // required int32 context_id = 1;
-  inline bool has_context_id() const;
-  inline void clear_context_id();
-  static const int kContextIdFieldNumber = 1;
-  inline ::google::protobuf::int32 context_id() const;
-  inline void set_context_id(::google::protobuf::int32 value);
-  
-  // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
-  inline bool has_function() const;
-  inline void clear_function();
-  static const int kFunctionFieldNumber = 2;
-  inline ::com::android::glesv2debugger::Message_Function function() const;
-  inline void set_function(::com::android::glesv2debugger::Message_Function value);
-  
-  // required .com.android.glesv2debugger.Message.Type type = 3;
-  inline bool has_type() const;
-  inline void clear_type();
-  static const int kTypeFieldNumber = 3;
-  inline ::com::android::glesv2debugger::Message_Type type() const;
-  inline void set_type(::com::android::glesv2debugger::Message_Type value);
-  
-  // required bool expect_response = 4;
-  inline bool has_expect_response() const;
-  inline void clear_expect_response();
-  static const int kExpectResponseFieldNumber = 4;
-  inline bool expect_response() const;
-  inline void set_expect_response(bool value);
-  
-  // optional int32 ret = 5;
-  inline bool has_ret() const;
-  inline void clear_ret();
-  static const int kRetFieldNumber = 5;
-  inline ::google::protobuf::int32 ret() const;
-  inline void set_ret(::google::protobuf::int32 value);
-  
-  // optional int32 arg0 = 6;
-  inline bool has_arg0() const;
-  inline void clear_arg0();
-  static const int kArg0FieldNumber = 6;
-  inline ::google::protobuf::int32 arg0() const;
-  inline void set_arg0(::google::protobuf::int32 value);
-  
-  // optional int32 arg1 = 7;
-  inline bool has_arg1() const;
-  inline void clear_arg1();
-  static const int kArg1FieldNumber = 7;
-  inline ::google::protobuf::int32 arg1() const;
-  inline void set_arg1(::google::protobuf::int32 value);
-  
-  // optional int32 arg2 = 8;
-  inline bool has_arg2() const;
-  inline void clear_arg2();
-  static const int kArg2FieldNumber = 8;
-  inline ::google::protobuf::int32 arg2() const;
-  inline void set_arg2(::google::protobuf::int32 value);
-  
-  // optional int32 arg3 = 9;
-  inline bool has_arg3() const;
-  inline void clear_arg3();
-  static const int kArg3FieldNumber = 9;
-  inline ::google::protobuf::int32 arg3() const;
-  inline void set_arg3(::google::protobuf::int32 value);
-  
-  // optional int32 arg4 = 16;
-  inline bool has_arg4() const;
-  inline void clear_arg4();
-  static const int kArg4FieldNumber = 16;
-  inline ::google::protobuf::int32 arg4() const;
-  inline void set_arg4(::google::protobuf::int32 value);
-  
-  // optional int32 arg5 = 17;
-  inline bool has_arg5() const;
-  inline void clear_arg5();
-  static const int kArg5FieldNumber = 17;
-  inline ::google::protobuf::int32 arg5() const;
-  inline void set_arg5(::google::protobuf::int32 value);
-  
-  // optional int32 arg6 = 18;
-  inline bool has_arg6() const;
-  inline void clear_arg6();
-  static const int kArg6FieldNumber = 18;
-  inline ::google::protobuf::int32 arg6() const;
-  inline void set_arg6(::google::protobuf::int32 value);
-  
-  // optional int32 arg7 = 19;
-  inline bool has_arg7() const;
-  inline void clear_arg7();
-  static const int kArg7FieldNumber = 19;
-  inline ::google::protobuf::int32 arg7() const;
-  inline void set_arg7(::google::protobuf::int32 value);
-  
-  // optional int32 arg8 = 20;
-  inline bool has_arg8() const;
-  inline void clear_arg8();
-  static const int kArg8FieldNumber = 20;
-  inline ::google::protobuf::int32 arg8() const;
-  inline void set_arg8(::google::protobuf::int32 value);
-  
-  // optional bytes data = 10;
-  inline bool has_data() const;
-  inline void clear_data();
-  static const int kDataFieldNumber = 10;
-  inline const ::std::string& data() const;
-  inline void set_data(const ::std::string& value);
-  inline void set_data(const char* value);
-  inline void set_data(const void* value, size_t size);
-  inline ::std::string* mutable_data();
-  
-  // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
-  inline bool has_data_type() const;
-  inline void clear_data_type();
-  static const int kDataTypeFieldNumber = 23;
-  inline ::com::android::glesv2debugger::Message_DataType data_type() const;
-  inline void set_data_type(::com::android::glesv2debugger::Message_DataType value);
-  
-  // optional int32 pixel_format = 24;
-  inline bool has_pixel_format() const;
-  inline void clear_pixel_format();
-  static const int kPixelFormatFieldNumber = 24;
-  inline ::google::protobuf::int32 pixel_format() const;
-  inline void set_pixel_format(::google::protobuf::int32 value);
-  
-  // optional int32 pixel_type = 25;
-  inline bool has_pixel_type() const;
-  inline void clear_pixel_type();
-  static const int kPixelTypeFieldNumber = 25;
-  inline ::google::protobuf::int32 pixel_type() const;
-  inline void set_pixel_type(::google::protobuf::int32 value);
-  
-  // optional int32 image_width = 26;
-  inline bool has_image_width() const;
-  inline void clear_image_width();
-  static const int kImageWidthFieldNumber = 26;
-  inline ::google::protobuf::int32 image_width() const;
-  inline void set_image_width(::google::protobuf::int32 value);
-  
-  // optional int32 image_height = 27;
-  inline bool has_image_height() const;
-  inline void clear_image_height();
-  static const int kImageHeightFieldNumber = 27;
-  inline ::google::protobuf::int32 image_height() const;
-  inline void set_image_height(::google::protobuf::int32 value);
-  
-  // optional float time = 11;
-  inline bool has_time() const;
-  inline void clear_time();
-  static const int kTimeFieldNumber = 11;
-  inline float time() const;
-  inline void set_time(float value);
-  
-  // optional .com.android.glesv2debugger.Message.Prop prop = 21;
-  inline bool has_prop() const;
-  inline void clear_prop();
-  static const int kPropFieldNumber = 21;
-  inline ::com::android::glesv2debugger::Message_Prop prop() const;
-  inline void set_prop(::com::android::glesv2debugger::Message_Prop value);
-  
-  // optional float clock = 22;
-  inline bool has_clock() const;
-  inline void clear_clock();
-  static const int kClockFieldNumber = 22;
-  inline float clock() const;
-  inline void set_clock(float value);
-  
-  // @@protoc_insertion_point(class_scope:com.android.glesv2debugger.Message)
- private:
-  mutable int _cached_size_;
-  
-  ::google::protobuf::int32 context_id_;
-  int function_;
-  int type_;
-  bool expect_response_;
-  ::google::protobuf::int32 ret_;
-  ::google::protobuf::int32 arg0_;
-  ::google::protobuf::int32 arg1_;
-  ::google::protobuf::int32 arg2_;
-  ::google::protobuf::int32 arg3_;
-  ::google::protobuf::int32 arg4_;
-  ::google::protobuf::int32 arg5_;
-  ::google::protobuf::int32 arg6_;
-  ::google::protobuf::int32 arg7_;
-  ::google::protobuf::int32 arg8_;
-  ::std::string* data_;
-  static const ::std::string _default_data_;
-  int data_type_;
-  ::google::protobuf::int32 pixel_format_;
-  ::google::protobuf::int32 pixel_type_;
-  ::google::protobuf::int32 image_width_;
-  ::google::protobuf::int32 image_height_;
-  float time_;
-  int prop_;
-  float clock_;
-  friend void  protobuf_AddDesc_debugger_5fmessage_2eproto();
-  friend void protobuf_AssignDesc_debugger_5fmessage_2eproto();
-  friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
-  
-  ::google::protobuf::uint32 _has_bits_[(23 + 31) / 32];
-  
-  // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
-  inline bool _has_bit(int index) const {
-    return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
-  }
-  inline void _set_bit(int index) {
-    _has_bits_[index / 32] |= (1u << (index % 32));
-  }
-  inline void _clear_bit(int index) {
-    _has_bits_[index / 32] &= ~(1u << (index % 32));
-  }
-  
-  void InitAsDefaultInstance();
-  static Message* default_instance_;
-};
-// ===================================================================
-
-
-// ===================================================================
-
-// Message
-
-// required int32 context_id = 1;
-inline bool Message::has_context_id() const {
-  return _has_bit(0);
-}
-inline void Message::clear_context_id() {
-  context_id_ = 0;
-  _clear_bit(0);
-}
-inline ::google::protobuf::int32 Message::context_id() const {
-  return context_id_;
-}
-inline void Message::set_context_id(::google::protobuf::int32 value) {
-  _set_bit(0);
-  context_id_ = value;
-}
-
-// required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
-inline bool Message::has_function() const {
-  return _has_bit(1);
-}
-inline void Message::clear_function() {
-  function_ = 187;
-  _clear_bit(1);
-}
-inline ::com::android::glesv2debugger::Message_Function Message::function() const {
-  return static_cast< ::com::android::glesv2debugger::Message_Function >(function_);
-}
-inline void Message::set_function(::com::android::glesv2debugger::Message_Function value) {
-  GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Function_IsValid(value));
-  _set_bit(1);
-  function_ = value;
-}
-
-// required .com.android.glesv2debugger.Message.Type type = 3;
-inline bool Message::has_type() const {
-  return _has_bit(2);
-}
-inline void Message::clear_type() {
-  type_ = 0;
-  _clear_bit(2);
-}
-inline ::com::android::glesv2debugger::Message_Type Message::type() const {
-  return static_cast< ::com::android::glesv2debugger::Message_Type >(type_);
-}
-inline void Message::set_type(::com::android::glesv2debugger::Message_Type value) {
-  GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Type_IsValid(value));
-  _set_bit(2);
-  type_ = value;
-}
-
-// required bool expect_response = 4;
-inline bool Message::has_expect_response() const {
-  return _has_bit(3);
-}
-inline void Message::clear_expect_response() {
-  expect_response_ = false;
-  _clear_bit(3);
-}
-inline bool Message::expect_response() const {
-  return expect_response_;
-}
-inline void Message::set_expect_response(bool value) {
-  _set_bit(3);
-  expect_response_ = value;
-}
-
-// optional int32 ret = 5;
-inline bool Message::has_ret() const {
-  return _has_bit(4);
-}
-inline void Message::clear_ret() {
-  ret_ = 0;
-  _clear_bit(4);
-}
-inline ::google::protobuf::int32 Message::ret() const {
-  return ret_;
-}
-inline void Message::set_ret(::google::protobuf::int32 value) {
-  _set_bit(4);
-  ret_ = value;
-}
-
-// optional int32 arg0 = 6;
-inline bool Message::has_arg0() const {
-  return _has_bit(5);
-}
-inline void Message::clear_arg0() {
-  arg0_ = 0;
-  _clear_bit(5);
-}
-inline ::google::protobuf::int32 Message::arg0() const {
-  return arg0_;
-}
-inline void Message::set_arg0(::google::protobuf::int32 value) {
-  _set_bit(5);
-  arg0_ = value;
-}
-
-// optional int32 arg1 = 7;
-inline bool Message::has_arg1() const {
-  return _has_bit(6);
-}
-inline void Message::clear_arg1() {
-  arg1_ = 0;
-  _clear_bit(6);
-}
-inline ::google::protobuf::int32 Message::arg1() const {
-  return arg1_;
-}
-inline void Message::set_arg1(::google::protobuf::int32 value) {
-  _set_bit(6);
-  arg1_ = value;
-}
-
-// optional int32 arg2 = 8;
-inline bool Message::has_arg2() const {
-  return _has_bit(7);
-}
-inline void Message::clear_arg2() {
-  arg2_ = 0;
-  _clear_bit(7);
-}
-inline ::google::protobuf::int32 Message::arg2() const {
-  return arg2_;
-}
-inline void Message::set_arg2(::google::protobuf::int32 value) {
-  _set_bit(7);
-  arg2_ = value;
-}
-
-// optional int32 arg3 = 9;
-inline bool Message::has_arg3() const {
-  return _has_bit(8);
-}
-inline void Message::clear_arg3() {
-  arg3_ = 0;
-  _clear_bit(8);
-}
-inline ::google::protobuf::int32 Message::arg3() const {
-  return arg3_;
-}
-inline void Message::set_arg3(::google::protobuf::int32 value) {
-  _set_bit(8);
-  arg3_ = value;
-}
-
-// optional int32 arg4 = 16;
-inline bool Message::has_arg4() const {
-  return _has_bit(9);
-}
-inline void Message::clear_arg4() {
-  arg4_ = 0;
-  _clear_bit(9);
-}
-inline ::google::protobuf::int32 Message::arg4() const {
-  return arg4_;
-}
-inline void Message::set_arg4(::google::protobuf::int32 value) {
-  _set_bit(9);
-  arg4_ = value;
-}
-
-// optional int32 arg5 = 17;
-inline bool Message::has_arg5() const {
-  return _has_bit(10);
-}
-inline void Message::clear_arg5() {
-  arg5_ = 0;
-  _clear_bit(10);
-}
-inline ::google::protobuf::int32 Message::arg5() const {
-  return arg5_;
-}
-inline void Message::set_arg5(::google::protobuf::int32 value) {
-  _set_bit(10);
-  arg5_ = value;
-}
-
-// optional int32 arg6 = 18;
-inline bool Message::has_arg6() const {
-  return _has_bit(11);
-}
-inline void Message::clear_arg6() {
-  arg6_ = 0;
-  _clear_bit(11);
-}
-inline ::google::protobuf::int32 Message::arg6() const {
-  return arg6_;
-}
-inline void Message::set_arg6(::google::protobuf::int32 value) {
-  _set_bit(11);
-  arg6_ = value;
-}
-
-// optional int32 arg7 = 19;
-inline bool Message::has_arg7() const {
-  return _has_bit(12);
-}
-inline void Message::clear_arg7() {
-  arg7_ = 0;
-  _clear_bit(12);
-}
-inline ::google::protobuf::int32 Message::arg7() const {
-  return arg7_;
-}
-inline void Message::set_arg7(::google::protobuf::int32 value) {
-  _set_bit(12);
-  arg7_ = value;
-}
-
-// optional int32 arg8 = 20;
-inline bool Message::has_arg8() const {
-  return _has_bit(13);
-}
-inline void Message::clear_arg8() {
-  arg8_ = 0;
-  _clear_bit(13);
-}
-inline ::google::protobuf::int32 Message::arg8() const {
-  return arg8_;
-}
-inline void Message::set_arg8(::google::protobuf::int32 value) {
-  _set_bit(13);
-  arg8_ = value;
-}
-
-// optional bytes data = 10;
-inline bool Message::has_data() const {
-  return _has_bit(14);
-}
-inline void Message::clear_data() {
-  if (data_ != &_default_data_) {
-    data_->clear();
-  }
-  _clear_bit(14);
-}
-inline const ::std::string& Message::data() const {
-  return *data_;
-}
-inline void Message::set_data(const ::std::string& value) {
-  _set_bit(14);
-  if (data_ == &_default_data_) {
-    data_ = new ::std::string;
-  }
-  data_->assign(value);
-}
-inline void Message::set_data(const char* value) {
-  _set_bit(14);
-  if (data_ == &_default_data_) {
-    data_ = new ::std::string;
-  }
-  data_->assign(value);
-}
-inline void Message::set_data(const void* value, size_t size) {
-  _set_bit(14);
-  if (data_ == &_default_data_) {
-    data_ = new ::std::string;
-  }
-  data_->assign(reinterpret_cast<const char*>(value), size);
-}
-inline ::std::string* Message::mutable_data() {
-  _set_bit(14);
-  if (data_ == &_default_data_) {
-    data_ = new ::std::string;
-  }
-  return data_;
-}
-
-// optional .com.android.glesv2debugger.Message.DataType data_type = 23;
-inline bool Message::has_data_type() const {
-  return _has_bit(15);
-}
-inline void Message::clear_data_type() {
-  data_type_ = 0;
-  _clear_bit(15);
-}
-inline ::com::android::glesv2debugger::Message_DataType Message::data_type() const {
-  return static_cast< ::com::android::glesv2debugger::Message_DataType >(data_type_);
-}
-inline void Message::set_data_type(::com::android::glesv2debugger::Message_DataType value) {
-  GOOGLE_DCHECK(::com::android::glesv2debugger::Message_DataType_IsValid(value));
-  _set_bit(15);
-  data_type_ = value;
-}
-
-// optional int32 pixel_format = 24;
-inline bool Message::has_pixel_format() const {
-  return _has_bit(16);
-}
-inline void Message::clear_pixel_format() {
-  pixel_format_ = 0;
-  _clear_bit(16);
-}
-inline ::google::protobuf::int32 Message::pixel_format() const {
-  return pixel_format_;
-}
-inline void Message::set_pixel_format(::google::protobuf::int32 value) {
-  _set_bit(16);
-  pixel_format_ = value;
-}
-
-// optional int32 pixel_type = 25;
-inline bool Message::has_pixel_type() const {
-  return _has_bit(17);
-}
-inline void Message::clear_pixel_type() {
-  pixel_type_ = 0;
-  _clear_bit(17);
-}
-inline ::google::protobuf::int32 Message::pixel_type() const {
-  return pixel_type_;
-}
-inline void Message::set_pixel_type(::google::protobuf::int32 value) {
-  _set_bit(17);
-  pixel_type_ = value;
-}
-
-// optional int32 image_width = 26;
-inline bool Message::has_image_width() const {
-  return _has_bit(18);
-}
-inline void Message::clear_image_width() {
-  image_width_ = 0;
-  _clear_bit(18);
-}
-inline ::google::protobuf::int32 Message::image_width() const {
-  return image_width_;
-}
-inline void Message::set_image_width(::google::protobuf::int32 value) {
-  _set_bit(18);
-  image_width_ = value;
-}
-
-// optional int32 image_height = 27;
-inline bool Message::has_image_height() const {
-  return _has_bit(19);
-}
-inline void Message::clear_image_height() {
-  image_height_ = 0;
-  _clear_bit(19);
-}
-inline ::google::protobuf::int32 Message::image_height() const {
-  return image_height_;
-}
-inline void Message::set_image_height(::google::protobuf::int32 value) {
-  _set_bit(19);
-  image_height_ = value;
-}
-
-// optional float time = 11;
-inline bool Message::has_time() const {
-  return _has_bit(20);
-}
-inline void Message::clear_time() {
-  time_ = 0;
-  _clear_bit(20);
-}
-inline float Message::time() const {
-  return time_;
-}
-inline void Message::set_time(float value) {
-  _set_bit(20);
-  time_ = value;
-}
-
-// optional .com.android.glesv2debugger.Message.Prop prop = 21;
-inline bool Message::has_prop() const {
-  return _has_bit(21);
-}
-inline void Message::clear_prop() {
-  prop_ = 0;
-  _clear_bit(21);
-}
-inline ::com::android::glesv2debugger::Message_Prop Message::prop() const {
-  return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_);
-}
-inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) {
-  GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value));
-  _set_bit(21);
-  prop_ = value;
-}
-
-// optional float clock = 22;
-inline bool Message::has_clock() const {
-  return _has_bit(22);
-}
-inline void Message::clear_clock() {
-  clock_ = 0;
-  _clear_bit(22);
-}
-inline float Message::clock() const {
-  return clock_;
-}
-inline void Message::set_clock(float value) {
-  _set_bit(22);
-  clock_ = value;
-}
-
-
-// @@protoc_insertion_point(namespace_scope)
-
-}  // namespace glesv2debugger
-}  // namespace android
-}  // namespace com
-
-// @@protoc_insertion_point(global_scope)
-
-#endif  // PROTOBUF_debugger_5fmessage_2eproto__INCLUDED
diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp
deleted file mode 100644
index bbea3bd..0000000
--- a/opengl/libs/GLES2_dbg/src/egl.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include "header.h"
-
-EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
-{
-    DbgContext * const dbg = getDbgContextThreadSpecific();
-    glesv2debugger::Message msg;
-    struct : public FunctionCall {
-        EGLDisplay dpy;
-        EGLSurface draw;
-
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            msg.set_time(-1);
-            return reinterpret_cast<const int *>(true);
-        }
-    } caller;
-    caller.dpy = dpy;
-    caller.draw = draw;
-
-    msg.set_arg0(reinterpret_cast<int>(dpy));
-    msg.set_arg1(reinterpret_cast<int>(draw));
-    if (dbg->captureSwap > 0) {
-        dbg->captureSwap--;
-        int viewport[4] = {};
-        dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
-        void * pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
-                        dbg->readBytesPerPixel);
-        dbg->hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2],
-                                    viewport[3], GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-        dbg->CompressReadPixelBuffer(msg.mutable_data());
-        msg.set_data_type(msg.ReferencedImage);
-        msg.set_pixel_format(GL_RGBA);
-        msg.set_pixel_type(GL_UNSIGNED_BYTE);
-        msg.set_image_width(viewport[2]);
-        msg.set_image_height(viewport[3]);
-    }
-    int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_eglSwapBuffers);
-    return static_cast<EGLBoolean>(reinterpret_cast<int>(ret));
-}
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
deleted file mode 100644
index 0ab4890..0000000
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#ifndef ANDROID_GLES2_DBG_HEADER_H
-#define ANDROID_GLES2_DBG_HEADER_H
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <cutils/log.h>
-#include <utils/Timers.h>
-
-#include "hooks.h"
-
-#include "glesv2dbg.h"
-
-#define GL_ENTRY(_r, _api, ...) _r Debug_##_api ( __VA_ARGS__ );
-#include "glesv2dbg_functions.h"
-
-#include "debugger_message.pb.h"
-
-using namespace android;
-using namespace com::android;
-
-#ifndef __location__
-#define __HIERALLOC_STRING_0__(s)   #s
-#define __HIERALLOC_STRING_1__(s)   __HIERALLOC_STRING_0__(s)
-#define __HIERALLOC_STRING_2__      __HIERALLOC_STRING_1__(__LINE__)
-#define __location__                __FILE__ ":" __HIERALLOC_STRING_2__
-#endif
-
-#undef assert
-#define assert(expr) if (!(expr)) { ALOGD("\n*\n*\n* assert: %s at %s \n*\n*", #expr, __location__); int * x = 0; *x = 5; }
-//#undef ALOGD
-//#define ALOGD(...)
-
-namespace android
-{
-
-struct GLFunctionBitfield {
-    unsigned char field [24]; // 8 * 24 = 192
-
-    void Bit(const glesv2debugger::Message_Function function, bool bit) {
-        const unsigned byte = function / 8, mask = 1 << (function % 8);
-        if (bit)
-            field[byte] |= mask;
-        else
-            field[byte] &= ~mask;
-    }
-
-    bool Bit(const glesv2debugger::Message_Function function) const {
-        const unsigned byte = function / 8, mask = 1 << (function % 8);
-        return field[byte] & mask;
-    }
-};
-
-struct DbgContext {
-    static const unsigned int LZF_CHUNK_SIZE = 256 * 1024;
-
-private:
-    char * lzf_buf; // malloc / free; for lzf chunk compression and other uses
-
-    // used as buffer and reference frame for ReadPixels; malloc/free
-    unsigned * lzf_ref [2];
-    unsigned lzf_readIndex; // 0 or 1
-    unsigned lzf_refSize, lzf_refBufSize; // bytes
-
-public:
-    const unsigned int version; // 0 is GLES1, 1 is GLES2
-    const gl_hooks_t * const hooks;
-    const unsigned int MAX_VERTEX_ATTRIBS;
-    const unsigned int readBytesPerPixel;
-
-    unsigned int captureSwap; // number of eglSwapBuffers to glReadPixels
-    unsigned int captureDraw; // number of glDrawArrays/Elements to glReadPixels
-
-    GLFunctionBitfield expectResponse;
-
-    struct VertexAttrib {
-        GLenum type; // element data type
-        unsigned size; // number of data per element
-        unsigned stride; // calculated number of bytes between elements
-        const void * ptr;
-        unsigned elemSize; // calculated number of bytes per element
-        GLuint buffer; // buffer name
-        GLboolean normalized : 1;
-        GLboolean enabled : 1;
-        VertexAttrib() : type(0), size(0), stride(0), ptr(NULL), elemSize(0),
-                buffer(0), normalized(0), enabled(0) {}
-    } * vertexAttribs;
-    bool hasNonVBOAttribs; // whether any enabled vertexAttrib is user pointer
-
-    struct VBO {
-        const GLuint name;
-        const GLenum target;
-        VBO * next;
-        void * data; // malloc/free
-        unsigned size; // in bytes
-        VBO(const GLuint name, const GLenum target, VBO * head) : name(name),
-                target(target), next(head), data(NULL), size(0) {}
-    } * indexBuffers; // linked list of all index buffers
-    VBO * indexBuffer; // currently bound index buffer
-
-    GLuint program;
-    unsigned maxAttrib; // number of slots used by program
-
-    DbgContext(const unsigned version, const gl_hooks_t * const hooks,
-               const unsigned MAX_VERTEX_ATTRIBS);
-    ~DbgContext();
-
-    void Fetch(const unsigned index, std::string * const data) const;
-    void Compress(const void * in_data, unsigned in_len, std::string * const outStr);
-    static unsigned char * Decompress(const void * in, const unsigned int inLen,
-                                      unsigned int * const outLen); // malloc/free
-    void * GetReadPixelsBuffer(const unsigned size);
-    bool IsReadPixelBuffer(const void * const ptr)  {
-        return ptr == lzf_ref[lzf_readIndex];
-    }
-    void CompressReadPixelBuffer(std::string * const outStr);
-    char * GetBuffer(); // allocates lzf_buf if NULL
-    unsigned int GetBufferSize(); // allocates lzf_buf if NULL
-
-    void glUseProgram(GLuint program);
-    void glEnableVertexAttribArray(GLuint index);
-    void glDisableVertexAttribArray(GLuint index);
-    void glVertexAttribPointer(GLuint indx, GLint size, GLenum type,
-                               GLboolean normalized, GLsizei stride, const GLvoid* ptr);
-    void glBindBuffer(GLenum target, GLuint buffer);
-    void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
-    void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
-    void glDeleteBuffers(GLsizei n, const GLuint *buffers);
-};
-
-DbgContext * getDbgContextThreadSpecific();
-
-struct FunctionCall {
-    virtual const int * operator()(gl_hooks_t::gl_t const * const _c,
-                                   glesv2debugger::Message & msg) = 0;
-    virtual ~FunctionCall() {}
-};
-
-// move these into DbgContext as static
-extern int timeMode; // SYSTEM_TIME_
-
-extern int clientSock, serverSock;
-
-unsigned GetBytesPerPixel(const GLenum format, const GLenum type);
-
-// every Debug_gl* function calls this to send message to client and possibly receive commands
-int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
-                  const glesv2debugger::Message_Function function);
-
-void Receive(glesv2debugger::Message & cmd);
-float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd);
-void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd);
-const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
-                         glesv2debugger::Message & msg, const int * const prevRet);
-}; // namespace android {
-
-#endif // #ifndef ANDROID_GLES2_DBG_HEADER_H
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
deleted file mode 100644
index 3e93697..0000000
--- a/opengl/libs/GLES2_dbg/src/server.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <pthread.h>
-
-#include "header.h"
-
-namespace android
-{
-
-int serverSock = -1, clientSock = -1;
-FILE * file = NULL;
-unsigned int MAX_FILE_SIZE = 0;
-int timeMode = SYSTEM_TIME_THREAD;
-
-static void Die(const char * msg)
-{
-    ALOGD("\n*\n*\n* GLESv2_dbg: Die: %s \n*\n*", msg);
-    StopDebugServer();
-    exit(1);
-}
-
-void StartDebugServer(const unsigned short port, const bool forceUseFile,
-                      const unsigned int maxFileSize, const char * const filePath)
-{
-    MAX_FILE_SIZE = maxFileSize;
-
-    ALOGD("GLESv2_dbg: StartDebugServer");
-    if (serverSock >= 0 || file)
-        return;
-
-    ALOGD("GLESv2_dbg: StartDebugServer create socket");
-    struct sockaddr_in server = {}, client = {};
-
-    /* Create the TCP socket */
-    if (forceUseFile || (serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
-        file = fopen(filePath, "wb");
-        if (!file)
-            Die("Failed to create socket and file");
-        else
-            return;
-    }
-    /* Construct the server sockaddr_in structure */
-    server.sin_family = AF_INET;                  /* Internet/IP */
-    server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);   /* Incoming addr */
-    server.sin_port = htons(port);       /* server port */
-
-    /* Bind the server socket */
-    socklen_t sizeofSockaddr_in = sizeof(sockaddr_in);
-    if (bind(serverSock, (struct sockaddr *) &server,
-             sizeof(server)) < 0) {
-        Die("Failed to bind the server socket");
-    }
-    /* Listen on the server socket */
-    if (listen(serverSock, 1) < 0) {
-        Die("Failed to listen on server socket");
-    }
-
-    ALOGD("server started on %d \n", server.sin_port);
-
-
-    /* Wait for client connection */
-    if ((clientSock =
-                accept(serverSock, (struct sockaddr *) &client,
-                       &sizeofSockaddr_in)) < 0) {
-        Die("Failed to accept client connection");
-    }
-
-    ALOGD("Client connected: %s\n", inet_ntoa(client.sin_addr));
-//    fcntl(clientSock, F_SETFL, O_NONBLOCK);
-}
-
-void StopDebugServer()
-{
-    ALOGD("GLESv2_dbg: StopDebugServer");
-    if (clientSock > 0) {
-        close(clientSock);
-        clientSock = -1;
-    }
-    if (serverSock > 0) {
-        close(serverSock);
-        serverSock = -1;
-    }
-    if (file) {
-        fclose(file);
-        file = NULL;
-    }
-}
-
-void Receive(glesv2debugger::Message & cmd)
-{
-    if (clientSock < 0)
-        return;
-    unsigned len = 0;
-    int received = recv(clientSock, &len, 4, MSG_WAITALL);
-    if (received < 0)
-        Die("Failed to receive response length");
-    else if (4 != received) {
-        ALOGD("received %dB: %.8X", received, len);
-        Die("Received length mismatch, expected 4");
-    }
-    static void * buffer = NULL;
-    static unsigned bufferSize = 0;
-    if (bufferSize < len) {
-        buffer = realloc(buffer, len);
-        assert(buffer);
-        bufferSize = len;
-    }
-    received = recv(clientSock, buffer, len, MSG_WAITALL);
-    if (received < 0)
-        Die("Failed to receive response");
-    else if (len != received)
-        Die("Received length mismatch");
-    cmd.Clear();
-    cmd.ParseFromArray(buffer, len);
-}
-
-bool TryReceive(glesv2debugger::Message & cmd)
-{
-    if (clientSock < 0)
-        return false;
-    fd_set readSet;
-    FD_ZERO(&readSet);
-    FD_SET(clientSock, &readSet);
-    timeval timeout;
-    timeout.tv_sec = timeout.tv_usec = 0;
-
-    int rc = select(clientSock + 1, &readSet, NULL, NULL, &timeout);
-    if (rc < 0)
-        Die("failed to select clientSock");
-
-    bool received = false;
-    if (FD_ISSET(clientSock, &readSet)) {
-        ALOGD("TryReceive: avaiable for read");
-        Receive(cmd);
-        return true;
-    }
-    return false;
-}
-
-float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
-{
-    // TODO: use per DbgContext send/receive buffer and async socket
-    //  instead of mutex and blocking io; watch out for large messages
-    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-    struct Autolock {
-        Autolock() {
-            pthread_mutex_lock(&mutex);
-        }
-        ~Autolock() {
-            pthread_mutex_unlock(&mutex);
-        }
-    } autolock;
-
-    if (msg.function() != glesv2debugger::Message_Function_ACK)
-        assert(msg.has_context_id() && msg.context_id() != 0);
-    static std::string str;
-    msg.SerializeToString(&str);
-    const uint32_t len = str.length();
-    if (clientSock < 0) {
-        if (file) {
-            fwrite(&len, sizeof(len), 1, file);
-            fwrite(str.data(), len, 1, file);
-            if (ftell(file) >= MAX_FILE_SIZE) {
-                fclose(file);
-                Die("MAX_FILE_SIZE reached");
-            }
-        }
-        return 0;
-    }
-    int sent = -1;
-    sent = send(clientSock, &len, sizeof(len), 0);
-    if (sent != sizeof(len)) {
-        ALOGD("actual sent=%d expected=%d clientSock=%d", sent, sizeof(len), clientSock);
-        Die("Failed to send message length");
-    }
-    nsecs_t c0 = systemTime(timeMode);
-    sent = send(clientSock, str.data(), str.length(), 0);
-    float t = (float)ns2ms(systemTime(timeMode) - c0);
-    if (sent != str.length()) {
-        ALOGD("actual sent=%d expected=%d clientSock=%d", sent, str.length(), clientSock);
-        Die("Failed to send message");
-    }
-    // TODO: factor Receive & TryReceive out and into MessageLoop, or add control argument.
-    // mean while, if server is sending a SETPROP then don't try to receive,
-    //  because server will not be processing received command
-    if (msg.function() == msg.SETPROP)
-        return t;
-    // try to receive commands even though not expecting response,
-    //  since client can send SETPROP and other commands anytime
-    if (!msg.expect_response()) {
-        if (TryReceive(cmd)) {
-            if (glesv2debugger::Message_Function_SETPROP == cmd.function())
-                ALOGD("Send: TryReceived SETPROP");
-            else
-                ALOGD("Send: TryReceived %u", cmd.function());
-        }
-    } else
-        Receive(cmd);
-    return t;
-}
-
-void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)
-{
-    switch (cmd.prop()) {
-    case glesv2debugger::Message_Prop_CaptureDraw:
-        ALOGD("SetProp Message_Prop_CaptureDraw %d", cmd.arg0());
-        dbg->captureDraw = cmd.arg0();
-        break;
-    case glesv2debugger::Message_Prop_TimeMode:
-        ALOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0());
-        timeMode = cmd.arg0();
-        break;
-    case glesv2debugger::Message_Prop_ExpectResponse:
-        ALOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1());
-        dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1());
-        break;
-    case glesv2debugger::Message_Prop_CaptureSwap:
-        ALOGD("SetProp CaptureSwap %d", cmd.arg0());
-        dbg->captureSwap = cmd.arg0();
-        break;
-    default:
-        assert(0);
-    }
-}
-
-int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
-                  const glesv2debugger::Message_Function function)
-{
-    DbgContext * const dbg = getDbgContextThreadSpecific();
-    const int * ret = 0;
-    glesv2debugger::Message cmd;
-    msg.set_context_id(reinterpret_cast<int>(dbg));
-    msg.set_type(glesv2debugger::Message_Type_BeforeCall);
-    bool expectResponse = dbg->expectResponse.Bit(function);
-    msg.set_expect_response(expectResponse);
-    msg.set_function(function);
-
-    // when not exectResponse, set cmd to CONTINUE then SKIP
-    // cmd will be overwritten by received command
-    cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
-    cmd.set_expect_response(expectResponse);
-    glesv2debugger::Message_Function oldCmd = cmd.function();
-    Send(msg, cmd);
-    expectResponse = cmd.expect_response();
-    while (true) {
-        msg.Clear();
-        nsecs_t c0 = systemTime(timeMode);
-        switch (cmd.function()) {
-        case glesv2debugger::Message_Function_CONTINUE:
-            ret = functionCall(&dbg->hooks->gl, msg);
-            while (GLenum error = dbg->hooks->gl.glGetError())
-                ALOGD("Function=%u glGetError() = 0x%.4X", function, error);
-            if (!msg.has_time()) // some has output data copy, so time inside call
-                msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.set_context_id(reinterpret_cast<int>(dbg));
-            msg.set_function(function);
-            msg.set_type(glesv2debugger::Message_Type_AfterCall);
-            msg.set_expect_response(expectResponse);
-            if (!expectResponse) {
-                cmd.set_function(glesv2debugger::Message_Function_SKIP);
-                cmd.set_expect_response(false);
-            }
-            oldCmd = cmd.function();
-            Send(msg, cmd);
-            expectResponse = cmd.expect_response();
-            break;
-        case glesv2debugger::Message_Function_SKIP:
-            return const_cast<int *>(ret);
-        case glesv2debugger::Message_Function_SETPROP:
-            SetProp(dbg, cmd);
-            expectResponse = cmd.expect_response();
-            if (!expectResponse) // SETPROP is "out of band"
-                cmd.set_function(oldCmd);
-            else
-                Receive(cmd);
-            break;
-        default:
-            ret = GenerateCall(dbg, cmd, msg, ret);
-            msg.set_expect_response(expectResponse);
-            if (!expectResponse) {
-                cmd.set_function(cmd.SKIP);
-                cmd.set_expect_response(expectResponse);
-            }
-            oldCmd = cmd.function();
-            Send(msg, cmd);
-            expectResponse = cmd.expect_response();
-            break;
-        }
-    }
-    return 0;
-}
-}; // namespace android {
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
deleted file mode 100644
index 70c3433..0000000
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include "header.h"
-
-namespace android
-{
-bool capture; // capture after each glDraw*
-}
-
-void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)
-{
-    DbgContext * const dbg = getDbgContextThreadSpecific();
-    glesv2debugger::Message msg, cmd;
-    msg.set_context_id(reinterpret_cast<int>(dbg));
-    msg.set_type(glesv2debugger::Message_Type_BeforeCall);
-    bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);
-    msg.set_expect_response(expectResponse);
-    msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
-    msg.set_arg0(mode);
-    msg.set_arg1(first);
-    msg.set_arg2(count);
-
-    msg.set_arg7(dbg->maxAttrib); // indicate capturing vertex data
-    if (dbg->hasNonVBOAttribs) {
-        std::string * const data = msg.mutable_data();
-        for (unsigned i = 0; i < count; i++)
-            dbg->Fetch(i + first, data);
-    }
-
-    void * pixels = NULL;
-    int viewport[4] = {};
-    cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
-    cmd.set_expect_response(expectResponse);
-    glesv2debugger::Message_Function oldCmd = cmd.function();
-    Send(msg, cmd);
-    expectResponse = cmd.expect_response();
-    while (true) {
-        msg.Clear();
-        nsecs_t c0 = systemTime(timeMode);
-        switch (cmd.function()) {
-        case glesv2debugger::Message_Function_CONTINUE:
-            dbg->hooks->gl.glDrawArrays(mode, first, count);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.set_context_id(reinterpret_cast<int>(dbg));
-            msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
-            msg.set_type(glesv2debugger::Message_Type_AfterCall);
-            msg.set_expect_response(expectResponse);
-            if (!expectResponse) {
-                cmd.set_function(glesv2debugger::Message_Function_SKIP);
-                cmd.set_expect_response(false);
-            }
-            oldCmd = cmd.function();
-            Send(msg, cmd);
-            expectResponse = cmd.expect_response();
-            // TODO: pack glReadPixels data with vertex data instead of
-            //  relying on sperate call for transport, this would allow
-            //  auto generated message loop using EXTEND_Debug macro
-            if (dbg->captureDraw > 0) {
-                dbg->captureDraw--;
-                dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
-//                ALOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
-//                     viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
-                pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
-                                                  dbg->readBytesPerPixel);
-                Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
-                        GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-            }
-            break;
-        case glesv2debugger::Message_Function_SKIP:
-            return;
-        case glesv2debugger::Message_Function_SETPROP:
-            SetProp(dbg, cmd);
-            expectResponse = cmd.expect_response();
-            if (!expectResponse) // SETPROP is "out of band"
-                cmd.set_function(oldCmd);
-            else
-                Receive(cmd);
-            break;
-        default:
-            GenerateCall(dbg, cmd, msg, NULL);
-            msg.set_expect_response(expectResponse);
-            if (!expectResponse) {
-                cmd.set_function(cmd.SKIP);
-                cmd.set_expect_response(expectResponse);
-            }
-            oldCmd = cmd.function();
-            Send(msg, cmd);
-            expectResponse = cmd.expect_response();
-            break;
-        }
-    }
-}
-
-template<typename T>
-static inline void FetchIndexed(const unsigned count, const T * indices,
-                                std::string * const data, const DbgContext * const ctx)
-{
-    for (unsigned i = 0; i < count; i++) {
-        if (!ctx->indexBuffer)
-            data->append((const char *)(indices + i), sizeof(*indices));
-        if (ctx->hasNonVBOAttribs)
-            ctx->Fetch(indices[i], data);
-    }
-}
-
-void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
-{
-    DbgContext * const dbg = getDbgContextThreadSpecific();
-    glesv2debugger::Message msg, cmd;
-    msg.set_context_id(reinterpret_cast<int>(dbg));
-    msg.set_type(glesv2debugger::Message_Type_BeforeCall);
-    bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);
-    msg.set_expect_response(expectResponse);
-    msg.set_function(glesv2debugger::Message_Function_glDrawElements);
-    msg.set_arg0(mode);
-    msg.set_arg1(count);
-    msg.set_arg2(type);
-    msg.set_arg3(reinterpret_cast<int>(indices));
-
-    msg.set_arg7(dbg->maxAttrib); // indicate capturing vertex data
-    std::string * const data = msg.mutable_data();
-    if (GL_UNSIGNED_BYTE == type) {
-        if (dbg->indexBuffer) {
-            FetchIndexed(count, (unsigned char *)dbg->indexBuffer->data +
-                         (unsigned long)indices, data, dbg);
-        } else {
-            FetchIndexed(count, (unsigned char *)indices, data, dbg);
-        }
-    } else if (GL_UNSIGNED_SHORT == type) {
-        if (dbg->indexBuffer) {
-            FetchIndexed(count, (unsigned short *)((char *)dbg->indexBuffer->data +
-                                                   (unsigned long)indices), data, dbg);
-        } else {
-            FetchIndexed(count, (unsigned short *)indices, data, dbg);
-        }
-    } else {
-        assert(0);
-    }
-
-    void * pixels = NULL;
-    int viewport[4] = {};
-    cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
-    cmd.set_expect_response(expectResponse);
-    glesv2debugger::Message_Function oldCmd = cmd.function();
-    Send(msg, cmd);
-    expectResponse = cmd.expect_response();
-    while (true) {
-        msg.Clear();
-        nsecs_t c0 = systemTime(timeMode);
-        switch (cmd.function()) {
-        case glesv2debugger::Message_Function_CONTINUE:
-            dbg->hooks->gl.glDrawElements(mode, count, type, indices);
-            msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
-            msg.set_context_id(reinterpret_cast<int>(dbg));
-            msg.set_function(glesv2debugger::Message_Function_glDrawElements);
-            msg.set_type(glesv2debugger::Message_Type_AfterCall);
-            msg.set_expect_response(expectResponse);
-            if (!expectResponse) {
-                cmd.set_function(glesv2debugger::Message_Function_SKIP);
-                cmd.set_expect_response(false);
-            }
-            oldCmd = cmd.function();
-            Send(msg, cmd);
-            expectResponse = cmd.expect_response();
-            // TODO: pack glReadPixels data with vertex data instead of
-            //  relying on separate call for transport, this would allow
-            //  auto generated message loop using EXTEND_Debug macro
-            if (dbg->captureDraw > 0) {
-                dbg->captureDraw--;
-                dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
-                pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
-                                                  dbg->readBytesPerPixel);
-                Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
-                        GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-            }
-            break;
-        case glesv2debugger::Message_Function_SKIP:
-            return;
-        case glesv2debugger::Message_Function_SETPROP:
-            SetProp(dbg, cmd);
-            expectResponse = cmd.expect_response();
-            if (!expectResponse) // SETPROP is "out of band"
-                cmd.set_function(oldCmd);
-            else
-                Receive(cmd);
-            break;
-        default:
-            GenerateCall(dbg, cmd, msg, NULL);
-            msg.set_expect_response(expectResponse);
-            if (!expectResponse) {
-                cmd.set_function(cmd.SKIP);
-                cmd.set_expect_response(expectResponse);
-            }
-            oldCmd = cmd.function();
-            Send(msg, cmd);
-            expectResponse = cmd.expect_response();
-            break;
-        }
-    }
-}
diff --git a/opengl/libs/GLES2_dbg/test/Android.mk b/opengl/libs/GLES2_dbg/test/Android.mk
deleted file mode 100644
index 8708d43..0000000
--- a/opengl/libs/GLES2_dbg/test/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_C_INCLUDES := \
-    $(LOCAL_PATH) \
-    $(LOCAL_PATH)/../src \
-    $(LOCAL_PATH)/../../ \
-    external/gtest/include \
-    external/stlport/stlport \
-    external/protobuf/src \
-    bionic \
-    external \
-#
-
-LOCAL_SRC_FILES:= \
-    test_main.cpp \
-    test_server.cpp \
-    test_socket.cpp \
-#
-
-LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2_dbg libstlport
-LOCAL_STATIC_LIBRARIES := libgtest libprotobuf-cpp-2.3.0-lite liblzf
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE:= libGLESv2_dbg_test
-
-ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
-    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
-endif
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-include $(BUILD_EXECUTABLE)
-
diff --git a/opengl/libs/GLES2_dbg/test/test_main.cpp b/opengl/libs/GLES2_dbg/test/test_main.cpp
deleted file mode 100644
index 183bf8e..0000000
--- a/opengl/libs/GLES2_dbg/test/test_main.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include "header.h"
-#include "gtest/gtest.h"
-#include "hooks.h"
-
-namespace
-{
-
-// The fixture for testing class Foo.
-class DbgContextTest : public ::testing::Test
-{
-protected:
-    android::DbgContext dbg;
-    gl_hooks_t hooks;
-
-    DbgContextTest()
-            : dbg(1, &hooks, 32) {
-        // You can do set-up work for each test here.
-        hooks.gl.glGetError = GetError;
-    }
-
-    static GLenum GetError() {
-        return GL_NO_ERROR;
-    }
-
-    virtual ~DbgContextTest() {
-        // You can do clean-up work that doesn't throw exceptions here.
-    }
-
-    // If the constructor and destructor are not enough for setting up
-    // and cleaning up each test, you can define the following methods:
-
-    virtual void SetUp() {
-        // Code here will be called immediately after the constructor (right
-        // before each test).
-    }
-
-    virtual void TearDown() {
-        // Code here will be called immediately after each test (right
-        // before the destructor).
-    }
-};
-
-TEST_F(DbgContextTest, GetReadPixelBuffer)
-{
-    const unsigned int bufferSize = 512;
-    // test that it's allocating two buffers and swapping them
-    void * const buffer0 = dbg.GetReadPixelsBuffer(bufferSize);
-    ASSERT_NE((void *)NULL, buffer0);
-    for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) {
-        EXPECT_EQ(0, ((unsigned int *)buffer0)[i])
-        << "GetReadPixelsBuffer should allocate and zero";
-        ((unsigned int *)buffer0)[i] = i * 13;
-    }
-
-    void * const buffer1 = dbg.GetReadPixelsBuffer(bufferSize);
-    ASSERT_NE((void *)NULL, buffer1);
-    EXPECT_NE(buffer0, buffer1);
-    for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) {
-        EXPECT_EQ(0, ((unsigned int *)buffer1)[i])
-        << "GetReadPixelsBuffer should allocate and zero";
-        ((unsigned int *)buffer1)[i] = i * 17;
-    }
-
-    void * const buffer2 = dbg.GetReadPixelsBuffer(bufferSize);
-    EXPECT_EQ(buffer2, buffer0);
-    for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++)
-        EXPECT_EQ(i * 13, ((unsigned int *)buffer2)[i])
-        << "GetReadPixelsBuffer should swap buffers";
-
-    void * const buffer3 = dbg.GetReadPixelsBuffer(bufferSize);
-    EXPECT_EQ(buffer3, buffer1);
-    for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++)
-        EXPECT_EQ(i * 17, ((unsigned int *)buffer3)[i])
-        << "GetReadPixelsBuffer should swap buffers";
-
-    void * const buffer4 = dbg.GetReadPixelsBuffer(bufferSize);
-    EXPECT_NE(buffer3, buffer4);
-    EXPECT_EQ(buffer0, buffer2);
-    EXPECT_EQ(buffer1, buffer3);
-    EXPECT_EQ(buffer2, buffer4);
-
-    // it reallocs as necessary; 0 size may result in NULL
-    for (unsigned int i = 0; i < 42; i++) {
-        void * const buffer = dbg.GetReadPixelsBuffer(((i & 7)) << 20);
-        EXPECT_NE((void *)NULL, buffer)
-        << "should be able to get a variety of reasonable sizes";
-        EXPECT_TRUE(dbg.IsReadPixelBuffer(buffer));
-    }
-}
-
-TEST_F(DbgContextTest, CompressReadPixelBuffer)
-{
-    const unsigned int bufferSize = dbg.LZF_CHUNK_SIZE * 4 + 33;
-    std::string out;
-    unsigned char * buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
-    for (unsigned int i = 0; i < bufferSize; i++)
-        buffer[i] = i * 13;
-    dbg.CompressReadPixelBuffer(&out);
-    uint32_t decompSize = 0;
-    ASSERT_LT(12, out.length()); // at least written chunk header
-    ASSERT_EQ(bufferSize, *(uint32_t *)out.data())
-    << "total decompressed size should be as requested in GetReadPixelsBuffer";
-    for (unsigned int i = 4; i < out.length();) {
-        const uint32_t outSize = *(uint32_t *)(out.data() + i);
-        i += 4;
-        const uint32_t inSize = *(uint32_t *)(out.data() + i);
-        i += 4;
-        if (inSize == 0)
-            i += outSize; // chunk not compressed
-        else
-            i += inSize; // skip the actual compressed chunk
-        decompSize += outSize;
-    }
-    ASSERT_EQ(bufferSize, decompSize);
-    decompSize = 0;
-
-    unsigned char * decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
-    ASSERT_EQ(decompSize, bufferSize);
-    for (unsigned int i = 0; i < bufferSize; i++)
-        EXPECT_EQ((unsigned char)(i * 13), decomp[i]) << "xor with 0 ref is identity";
-    free(decomp);
-
-    buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
-    for (unsigned int i = 0; i < bufferSize; i++)
-        buffer[i] = i * 13;
-    out.clear();
-    dbg.CompressReadPixelBuffer(&out);
-    decompSize = 0;
-    decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
-    ASSERT_EQ(decompSize, bufferSize);
-    for (unsigned int i = 0; i < bufferSize; i++)
-        EXPECT_EQ(0, decomp[i]) << "xor with same ref is 0";
-    free(decomp);
-
-    buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
-    for (unsigned int i = 0; i < bufferSize; i++)
-        buffer[i] = i * 19;
-    out.clear();
-    dbg.CompressReadPixelBuffer(&out);
-    decompSize = 0;
-    decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
-    ASSERT_EQ(decompSize, bufferSize);
-    for (unsigned int i = 0; i < bufferSize; i++)
-        EXPECT_EQ((unsigned char)(i * 13) ^ (unsigned char)(i * 19), decomp[i])
-        << "xor ref";
-    free(decomp);
-}
-
-TEST_F(DbgContextTest, UseProgram)
-{
-    static const GLuint _program = 74568;
-    static const struct Attribute {
-        const char * name;
-        GLint location;
-        GLint size;
-        GLenum type;
-    } _attributes [] = {
-        {"aaa", 2, 2, GL_FLOAT_VEC2},
-        {"bb", 6, 2, GL_FLOAT_MAT2},
-        {"c", 1, 1, GL_FLOAT},
-    };
-    static const unsigned int _attributeCount = sizeof(_attributes) / sizeof(*_attributes);
-    struct GL {
-        static void GetProgramiv(GLuint program, GLenum pname, GLint* params) {
-            EXPECT_EQ(_program, program);
-            ASSERT_NE((GLint *)NULL, params);
-            switch (pname) {
-            case GL_ACTIVE_ATTRIBUTES:
-                *params = _attributeCount;
-                return;
-            case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
-                *params = 4; // includes NULL terminator
-                return;
-            default:
-                ADD_FAILURE() << "not handled pname: " << pname;
-            }
-        }
-
-        static GLint GetAttribLocation(GLuint program, const GLchar* name) {
-            EXPECT_EQ(_program, program);
-            for (unsigned int i = 0; i < _attributeCount; i++)
-                if (!strcmp(name, _attributes[i].name))
-                    return _attributes[i].location;
-            ADD_FAILURE() << "unknown attribute name: " << name;
-            return -1;
-        }
-
-        static void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
-                                    GLsizei* length, GLint* size, GLenum* type, GLchar* name) {
-            EXPECT_EQ(_program, program);
-            ASSERT_LT(index, _attributeCount);
-            const Attribute & att = _attributes[index];
-            ASSERT_GE(bufsize, strlen(att.name) + 1);
-            ASSERT_NE((GLint *)NULL, size);
-            ASSERT_NE((GLenum *)NULL, type);
-            ASSERT_NE((GLchar *)NULL, name);
-            strcpy(name, att.name);
-            if (length)
-                *length = strlen(name) + 1;
-            *size = att.size;
-            *type = att.type;
-        }
-    };
-    hooks.gl.glGetProgramiv = GL::GetProgramiv;
-    hooks.gl.glGetAttribLocation = GL::GetAttribLocation;
-    hooks.gl.glGetActiveAttrib = GL::GetActiveAttrib;
-    dbg.glUseProgram(_program);
-    EXPECT_EQ(10, dbg.maxAttrib);
-    dbg.glUseProgram(0);
-    EXPECT_EQ(0, dbg.maxAttrib);
-}
-}  // namespace
-
-int main(int argc, char **argv)
-{
-    ::testing::InitGoogleTest(&argc, argv);
-    return RUN_ALL_TESTS();
-}
diff --git a/opengl/libs/GLES2_dbg/test/test_server.cpp b/opengl/libs/GLES2_dbg/test/test_server.cpp
deleted file mode 100644
index 0ab87b0..0000000
--- a/opengl/libs/GLES2_dbg/test/test_server.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include "header.h"
-#include "gtest/gtest.h"
-#include "hooks.h"
-
-namespace android
-{
-extern FILE * file;
-extern unsigned int MAX_FILE_SIZE;
-};
-
-// tmpfile fails, so need to manually make a writable file first
-static const char * filePath = "/data/local/tmp/dump.gles2dbg";
-
-class ServerFileTest : public ::testing::Test
-{
-protected:
-    ServerFileTest() { }
-
-    virtual ~ServerFileTest() { }
-
-    virtual void SetUp() {
-        MAX_FILE_SIZE = 8 << 20;
-        ASSERT_EQ((FILE *)NULL, file);
-        file = fopen("/data/local/tmp/dump.gles2dbg", "wb+");
-        ASSERT_NE((FILE *)NULL, file) << "make sure file is writable: "
-        << filePath;
-    }
-
-    virtual void TearDown() {
-        ASSERT_NE((FILE *)NULL, file);
-        fclose(file);
-        file = NULL;
-    }
-
-    void Read(glesv2debugger::Message & msg) const {
-        msg.Clear();
-        uint32_t len = 0;
-        ASSERT_EQ(sizeof(len), fread(&len, 1, sizeof(len), file));
-        ASSERT_GT(len, 0u);
-        char * buffer = new char [len];
-        ASSERT_EQ(len, fread(buffer, 1, len, file));
-        msg.ParseFromArray(buffer, len);
-        delete buffer;
-    }
-
-    void CheckNoAvailable() {
-        const long pos = ftell(file);
-        fseek(file, 0, SEEK_END);
-        EXPECT_EQ(pos, ftell(file)) << "check no available";
-    }
-};
-
-TEST_F(ServerFileTest, Send)
-{
-    glesv2debugger::Message msg, cmd, read;
-    msg.set_context_id(1);
-    msg.set_function(msg.glFinish);
-    msg.set_expect_response(false);
-    msg.set_type(msg.BeforeCall);
-    rewind(file);
-    android::Send(msg, cmd);
-    rewind(file);
-    Read(read);
-    EXPECT_EQ(msg.context_id(), read.context_id());
-    EXPECT_EQ(msg.function(), read.function());
-    EXPECT_EQ(msg.expect_response(), read.expect_response());
-    EXPECT_EQ(msg.type(), read.type());
-}
-
-TEST_F(ServerFileTest, CreateDbgContext)
-{
-    gl_hooks_t hooks;
-    struct Constant {
-        GLenum pname;
-        GLint param;
-    };
-    static const Constant constants [] = {
-        {GL_MAX_VERTEX_ATTRIBS, 16},
-        {GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 32},
-        {GL_IMPLEMENTATION_COLOR_READ_FORMAT, GL_RGBA},
-        {GL_IMPLEMENTATION_COLOR_READ_TYPE, GL_UNSIGNED_BYTE},
-    };
-    struct HookMock {
-        static void GetIntegerv(GLenum pname, GLint* params) {
-            ASSERT_TRUE(params != NULL);
-            for (unsigned int i = 0; i < sizeof(constants) / sizeof(*constants); i++)
-                if (pname == constants[i].pname) {
-                    *params = constants[i].param;
-                    return;
-                }
-            FAIL() << "GetIntegerv unknown pname: " << pname;
-        }
-        static GLenum GetError() {
-            return GL_NO_ERROR;
-        }
-    };
-    hooks.gl.glGetError = HookMock::GetError;
-    hooks.gl.glGetIntegerv = HookMock::GetIntegerv;
-    DbgContext * const dbg = CreateDbgContext(1, &hooks);
-    ASSERT_TRUE(dbg != NULL);
-    EXPECT_TRUE(dbg->vertexAttribs != NULL);
-
-    rewind(file);
-    glesv2debugger::Message read;
-    for (unsigned int i = 0; i < 2; i++) {
-        Read(read);
-        EXPECT_EQ(reinterpret_cast<int>(dbg), read.context_id());
-        EXPECT_FALSE(read.expect_response());
-        EXPECT_EQ(read.Response, read.type());
-        EXPECT_EQ(read.SETPROP, read.function());
-        EXPECT_EQ(read.GLConstant, read.prop());
-        GLint expectedConstant = 0;
-        HookMock::GetIntegerv(read.arg0(), &expectedConstant);
-        EXPECT_EQ(expectedConstant, read.arg1());
-    }
-    CheckNoAvailable();
-    dbgReleaseThread();
-}
-
-void * glNoop()
-{
-    return 0;
-}
-
-class ServerFileContextTest : public ServerFileTest
-{
-protected:
-    DbgContext* dbg;
-    gl_hooks_t hooks;
-
-    ServerFileContextTest() { }
-
-    virtual ~ServerFileContextTest() { }
-
-    virtual void SetUp() {
-        ServerFileTest::SetUp();
-
-        dbg = new DbgContext(1, &hooks, 32);
-        ASSERT_NE((void *)NULL, dbg);
-        for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
-            ((void **)&hooks)[i] = reinterpret_cast<void *>(glNoop);
-    }
-
-    virtual void TearDown() {
-        ServerFileTest::TearDown();
-    }
-};
-
-TEST_F(ServerFileContextTest, MessageLoop)
-{
-    static const int arg0 = 45;
-    static const float arg7 = -87.2331f;
-    static const int arg8 = -3;
-    static const int * ret = reinterpret_cast<int *>(870);
-
-    struct Caller : public FunctionCall {
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            msg.set_arg0(arg0);
-            msg.set_arg7((int &)arg7);
-            msg.set_arg8(arg8);
-            return ret;
-        }
-    } caller;
-    const int contextId = reinterpret_cast<int>(dbg);
-    glesv2debugger::Message msg, read;
-
-    EXPECT_EQ(ret, MessageLoop(caller, msg, msg.glFinish));
-
-    rewind(file);
-    Read(read);
-    EXPECT_EQ(contextId, read.context_id());
-    EXPECT_EQ(read.glFinish, read.function());
-    EXPECT_EQ(false, read.expect_response());
-    EXPECT_EQ(read.BeforeCall, read.type());
-
-    Read(read);
-    EXPECT_EQ(contextId, read.context_id());
-    EXPECT_EQ(read.glFinish, read.function());
-    EXPECT_EQ(false, read.expect_response());
-    EXPECT_EQ(read.AfterCall, read.type());
-    EXPECT_TRUE(read.has_time());
-    EXPECT_EQ(arg0, read.arg0());
-    const int readArg7 = read.arg7();
-    EXPECT_EQ(arg7, (float &)readArg7);
-    EXPECT_EQ(arg8, read.arg8());
-
-    const long pos = ftell(file);
-    fseek(file, 0, SEEK_END);
-    EXPECT_EQ(pos, ftell(file))
-    << "should only write the BeforeCall and AfterCall messages";
-}
-
-TEST_F(ServerFileContextTest, DisableEnableVertexAttribArray)
-{
-    Debug_glEnableVertexAttribArray(dbg->MAX_VERTEX_ATTRIBS + 2); // should just ignore invalid index
-
-    glesv2debugger::Message read;
-    rewind(file);
-    Read(read);
-    EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
-    EXPECT_EQ(dbg->MAX_VERTEX_ATTRIBS + 2, read.arg0());
-    Read(read);
-
-    rewind(file);
-    Debug_glDisableVertexAttribArray(dbg->MAX_VERTEX_ATTRIBS + 4); // should just ignore invalid index
-    rewind(file);
-    Read(read);
-    Read(read);
-
-    for (unsigned int i = 0; i < dbg->MAX_VERTEX_ATTRIBS; i += 5) {
-        rewind(file);
-        Debug_glEnableVertexAttribArray(i);
-        EXPECT_TRUE(dbg->vertexAttribs[i].enabled);
-        rewind(file);
-        Read(read);
-        EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
-        EXPECT_EQ(i, read.arg0());
-        Read(read);
-
-        rewind(file);
-        Debug_glDisableVertexAttribArray(i);
-        EXPECT_FALSE(dbg->vertexAttribs[i].enabled);
-        rewind(file);
-        Read(read);
-        EXPECT_EQ(read.glDisableVertexAttribArray, read.function());
-        EXPECT_EQ(i, read.arg0());
-        Read(read);
-    }
-}
diff --git a/opengl/libs/GLES2_dbg/test/test_socket.cpp b/opengl/libs/GLES2_dbg/test/test_socket.cpp
deleted file mode 100644
index 9f815e2..0000000
--- a/opengl/libs/GLES2_dbg/test/test_socket.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- ** Copyright 2011, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-
-#include "header.h"
-#include "gtest/gtest.h"
-#include "hooks.h"
-
-namespace android
-{
-extern int serverSock, clientSock;
-};
-
-void * glNoop();
-
-class SocketContextTest : public ::testing::Test
-{
-protected:
-    DbgContext* dbg;
-    gl_hooks_t hooks;
-    int sock;
-    char * buffer;
-    unsigned int bufferSize;
-
-    SocketContextTest() : sock(-1) {
-    }
-
-    virtual ~SocketContextTest() {
-    }
-
-    virtual void SetUp() {
-        dbg = new DbgContext(1, &hooks, 32);
-        ASSERT_TRUE(dbg != NULL);
-        for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
-            ((void **)&hooks)[i] = (void *)glNoop;
-
-        int socks[2] = {-1, -1};
-        ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, socks));
-        clientSock = socks[0];
-        sock = socks[1];
-
-        bufferSize = 128;
-        buffer = new char [128];
-        ASSERT_NE((char *)NULL, buffer);
-    }
-
-    virtual void TearDown() {
-        close(sock);
-        close(clientSock);
-        clientSock = -1;
-        delete buffer;
-    }
-
-    void Write(glesv2debugger::Message & msg) const {
-        msg.set_context_id((int)dbg);
-        msg.set_type(msg.Response);
-        ASSERT_TRUE(msg.has_context_id());
-        ASSERT_TRUE(msg.has_function());
-        ASSERT_TRUE(msg.has_type());
-        ASSERT_TRUE(msg.has_expect_response());
-        static std::string str;
-        msg.SerializeToString(&str);
-        const uint32_t len = str.length();
-        ASSERT_EQ(sizeof(len), send(sock, &len, sizeof(len), 0));
-        ASSERT_EQ(str.length(), send(sock, str.data(), str.length(), 0));
-    }
-
-    void Read(glesv2debugger::Message & msg) {
-        int available = 0;
-        ASSERT_EQ(0, ioctl(sock, FIONREAD, &available));
-        ASSERT_GT(available, 0);
-        uint32_t len = 0;
-        ASSERT_EQ(sizeof(len), recv(sock, &len, sizeof(len), 0));
-        if (len > bufferSize) {
-            bufferSize = len;
-            buffer = new char[bufferSize];
-            ASSERT_TRUE(buffer != NULL);
-        }
-        ASSERT_EQ(len, recv(sock, buffer, len, 0));
-        msg.Clear();
-        msg.ParseFromArray(buffer, len);
-        ASSERT_TRUE(msg.has_context_id());
-        ASSERT_TRUE(msg.has_function());
-        ASSERT_TRUE(msg.has_type());
-        ASSERT_TRUE(msg.has_expect_response());
-    }
-
-    void CheckNoAvailable() {
-        int available = 0;
-        ASSERT_EQ(0, ioctl(sock, FIONREAD, &available));
-        ASSERT_EQ(available, 0);
-    }
-};
-
-TEST_F(SocketContextTest, MessageLoopSkip)
-{
-    static const int arg0 = 45;
-    static const float arg7 = -87.2331f;
-    static const int arg8 = -3;
-    static const int * ret = (int *)870;
-
-    struct Caller : public FunctionCall {
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            msg.set_arg0(arg0);
-            msg.set_arg7((int &)arg7);
-            msg.set_arg8(arg8);
-            return ret;
-        }
-    } caller;
-    glesv2debugger::Message msg, read, cmd;
-    dbg->expectResponse.Bit(msg.glFinish, true);
-
-    cmd.set_function(cmd.SKIP);
-    cmd.set_expect_response(false);
-    Write(cmd);
-
-    EXPECT_NE(ret, MessageLoop(caller, msg, msg.glFinish));
-
-    Read(read);
-    EXPECT_EQ(read.glFinish, read.function());
-    EXPECT_EQ(read.BeforeCall, read.type());
-    EXPECT_NE(arg0, read.arg0());
-    EXPECT_NE((int &)arg7, read.arg7());
-    EXPECT_NE(arg8, read.arg8());
-
-    CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, MessageLoopContinue)
-{
-    static const int arg0 = GL_FRAGMENT_SHADER;
-    static const int ret = -342;
-    struct Caller : public FunctionCall {
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            msg.set_ret(ret);
-            return (int *)ret;
-        }
-    } caller;
-    glesv2debugger::Message msg, read, cmd;
-    dbg->expectResponse.Bit(msg.glCreateShader, true);
-
-    cmd.set_function(cmd.CONTINUE);
-    cmd.set_expect_response(false); // MessageLoop should automatically skip after continue
-    Write(cmd);
-
-    msg.set_arg0(arg0);
-    EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateShader));
-
-    Read(read);
-    EXPECT_EQ(read.glCreateShader, read.function());
-    EXPECT_EQ(read.BeforeCall, read.type());
-    EXPECT_EQ(arg0, read.arg0());
-
-    Read(read);
-    EXPECT_EQ(read.glCreateShader, read.function());
-    EXPECT_EQ(read.AfterCall, read.type());
-    EXPECT_EQ(ret, read.ret());
-
-    CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, MessageLoopGenerateCall)
-{
-    static const int ret = -342;
-    static unsigned int createShader, createProgram;
-    createShader = 0;
-    createProgram = 0;
-    struct Caller : public FunctionCall {
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int r = (int)_c->glCreateProgram();
-            msg.set_ret(r);
-            return (int *)r;
-        }
-        static GLuint CreateShader(const GLenum type) {
-            createShader++;
-            return type;
-        }
-        static GLuint CreateProgram() {
-            createProgram++;
-            return ret;
-        }
-    } caller;
-    glesv2debugger::Message msg, read, cmd;
-    hooks.gl.glCreateShader = caller.CreateShader;
-    hooks.gl.glCreateProgram = caller.CreateProgram;
-    dbg->expectResponse.Bit(msg.glCreateProgram, true);
-
-    cmd.set_function(cmd.glCreateShader);
-    cmd.set_arg0(GL_FRAGMENT_SHADER);
-    cmd.set_expect_response(true);
-    Write(cmd);
-
-    cmd.Clear();
-    cmd.set_function(cmd.CONTINUE);
-    cmd.set_expect_response(true);
-    Write(cmd);
-
-    cmd.set_function(cmd.glCreateShader);
-    cmd.set_arg0(GL_VERTEX_SHADER);
-    cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards
-    Write(cmd);
-
-    EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram));
-
-    Read(read);
-    EXPECT_EQ(read.glCreateProgram, read.function());
-    EXPECT_EQ(read.BeforeCall, read.type());
-
-    Read(read);
-    EXPECT_EQ(read.glCreateShader, read.function());
-    EXPECT_EQ(read.AfterGeneratedCall, read.type());
-    EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret());
-
-    Read(read);
-    EXPECT_EQ(read.glCreateProgram, read.function());
-    EXPECT_EQ(read.AfterCall, read.type());
-    EXPECT_EQ(ret, read.ret());
-
-    Read(read);
-    EXPECT_EQ(read.glCreateShader, read.function());
-    EXPECT_EQ(read.AfterGeneratedCall, read.type());
-    EXPECT_EQ(GL_VERTEX_SHADER, read.ret());
-
-    EXPECT_EQ(2, createShader);
-    EXPECT_EQ(1, createProgram);
-
-    CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, MessageLoopSetProp)
-{
-    static const int ret = -342;
-    static unsigned int createShader, createProgram;
-    createShader = 0;
-    createProgram = 0;
-    struct Caller : public FunctionCall {
-        const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
-            const int r = (int)_c->glCreateProgram();
-            msg.set_ret(r);
-            return (int *)r;
-        }
-        static GLuint CreateShader(const GLenum type) {
-            createShader++;
-            return type;
-        }
-        static GLuint CreateProgram() {
-            createProgram++;
-            return ret;
-        }
-    } caller;
-    glesv2debugger::Message msg, read, cmd;
-    hooks.gl.glCreateShader = caller.CreateShader;
-    hooks.gl.glCreateProgram = caller.CreateProgram;
-    dbg->expectResponse.Bit(msg.glCreateProgram, false);
-
-    cmd.set_function(cmd.SETPROP);
-    cmd.set_prop(cmd.ExpectResponse);
-    cmd.set_arg0(cmd.glCreateProgram);
-    cmd.set_arg1(true);
-    cmd.set_expect_response(true);
-    Write(cmd);
-
-    cmd.Clear();
-    cmd.set_function(cmd.glCreateShader);
-    cmd.set_arg0(GL_FRAGMENT_SHADER);
-    cmd.set_expect_response(true);
-    Write(cmd);
-
-    cmd.set_function(cmd.SETPROP);
-    cmd.set_prop(cmd.CaptureDraw);
-    cmd.set_arg0(819);
-    cmd.set_expect_response(true);
-    Write(cmd);
-
-    cmd.Clear();
-    cmd.set_function(cmd.CONTINUE);
-    cmd.set_expect_response(true);
-    Write(cmd);
-
-    cmd.set_function(cmd.glCreateShader);
-    cmd.set_arg0(GL_VERTEX_SHADER);
-    cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards
-    Write(cmd);
-
-    EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram));
-
-    EXPECT_TRUE(dbg->expectResponse.Bit(msg.glCreateProgram));
-    EXPECT_EQ(819, dbg->captureDraw);
-
-    Read(read);
-    EXPECT_EQ(read.glCreateProgram, read.function());
-    EXPECT_EQ(read.BeforeCall, read.type());
-
-    Read(read);
-    EXPECT_EQ(read.glCreateShader, read.function());
-    EXPECT_EQ(read.AfterGeneratedCall, read.type());
-    EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret());
-
-    Read(read);
-    EXPECT_EQ(read.glCreateProgram, read.function());
-    EXPECT_EQ(read.AfterCall, read.type());
-    EXPECT_EQ(ret, read.ret());
-
-    Read(read);
-    EXPECT_EQ(read.glCreateShader, read.function());
-    EXPECT_EQ(read.AfterGeneratedCall, read.type());
-    EXPECT_EQ(GL_VERTEX_SHADER, read.ret());
-
-    EXPECT_EQ(2, createShader);
-    EXPECT_EQ(1, createProgram);
-
-    CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, TexImage2D)
-{
-    static const GLenum _target = GL_TEXTURE_2D;
-    static const GLint _level = 1, _internalformat = GL_RGBA;
-    static const GLsizei _width = 2, _height = 2;
-    static const GLint _border = 333;
-    static const GLenum _format = GL_RGB, _type = GL_UNSIGNED_SHORT_5_6_5;
-    static const short _pixels [_width * _height] = {11, 22, 33, 44};
-    static unsigned int texImage2D;
-    texImage2D = 0;
-
-    struct Caller {
-        static void TexImage2D(GLenum target, GLint level, GLint internalformat,
-                               GLsizei width, GLsizei height, GLint border,
-                               GLenum format, GLenum type, const GLvoid* pixels) {
-            EXPECT_EQ(_target, target);
-            EXPECT_EQ(_level, level);
-            EXPECT_EQ(_internalformat, internalformat);
-            EXPECT_EQ(_width, width);
-            EXPECT_EQ(_height, height);
-            EXPECT_EQ(_border, border);
-            EXPECT_EQ(_format, format);
-            EXPECT_EQ(_type, type);
-            EXPECT_EQ(0, memcmp(_pixels, pixels, sizeof(_pixels)));
-            texImage2D++;
-        }
-    } caller;
-    glesv2debugger::Message msg, read, cmd;
-    hooks.gl.glTexImage2D = caller.TexImage2D;
-    dbg->expectResponse.Bit(msg.glTexImage2D, false);
-
-    Debug_glTexImage2D(_target, _level, _internalformat, _width, _height, _border,
-                       _format, _type, _pixels);
-    EXPECT_EQ(1, texImage2D);
-
-    Read(read);
-    EXPECT_EQ(read.glTexImage2D, read.function());
-    EXPECT_EQ(read.BeforeCall, read.type());
-    EXPECT_EQ(_target, read.arg0());
-    EXPECT_EQ(_level, read.arg1());
-    EXPECT_EQ(_internalformat, read.arg2());
-    EXPECT_EQ(_width, read.arg3());
-    EXPECT_EQ(_height, read.arg4());
-    EXPECT_EQ(_border, read.arg5());
-    EXPECT_EQ(_format, read.arg6());
-    EXPECT_EQ(_type, read.arg7());
-
-    EXPECT_TRUE(read.has_data());
-    uint32_t dataLen = 0;
-    const unsigned char * data = dbg->Decompress(read.data().data(),
-                                 read.data().length(), &dataLen);
-    EXPECT_EQ(sizeof(_pixels), dataLen);
-    if (sizeof(_pixels) == dataLen)
-        EXPECT_EQ(0, memcmp(_pixels, data, sizeof(_pixels)));
-
-    Read(read);
-    EXPECT_EQ(read.glTexImage2D, read.function());
-    EXPECT_EQ(read.AfterCall, read.type());
-
-    CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, CopyTexImage2D)
-{
-    static const GLenum _target = GL_TEXTURE_2D;
-    static const GLint _level = 1, _internalformat = GL_RGBA;
-    static const GLint _x = 9, _y = 99;
-    static const GLsizei _width = 2, _height = 3;
-    static const GLint _border = 333;
-    static const int _pixels [_width * _height] = {11, 22, 33, 44, 55, 66};
-    static unsigned int copyTexImage2D, readPixels;
-    copyTexImage2D = 0, readPixels = 0;
-
-    struct Caller {
-        static void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
-                                   GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
-            EXPECT_EQ(_target, target);
-            EXPECT_EQ(_level, level);
-            EXPECT_EQ(_internalformat, internalformat);
-            EXPECT_EQ(_x, x);
-            EXPECT_EQ(_y, y);
-            EXPECT_EQ(_width, width);
-            EXPECT_EQ(_height, height);
-            EXPECT_EQ(_border, border);
-            copyTexImage2D++;
-        }
-        static void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
-                               GLenum format, GLenum type, GLvoid* pixels) {
-            EXPECT_EQ(_x, x);
-            EXPECT_EQ(_y, y);
-            EXPECT_EQ(_width, width);
-            EXPECT_EQ(_height, height);
-            EXPECT_EQ(GL_RGBA, format);
-            EXPECT_EQ(GL_UNSIGNED_BYTE, type);
-            ASSERT_TRUE(pixels != NULL);
-            memcpy(pixels, _pixels, sizeof(_pixels));
-            readPixels++;
-        }
-    } caller;
-    glesv2debugger::Message msg, read, cmd;
-    hooks.gl.glCopyTexImage2D = caller.CopyTexImage2D;
-    hooks.gl.glReadPixels = caller.ReadPixels;
-    dbg->expectResponse.Bit(msg.glCopyTexImage2D, false);
-
-    Debug_glCopyTexImage2D(_target, _level, _internalformat, _x, _y, _width, _height,
-                           _border);
-    ASSERT_EQ(1, copyTexImage2D);
-    ASSERT_EQ(1, readPixels);
-
-    Read(read);
-    EXPECT_EQ(read.glCopyTexImage2D, read.function());
-    EXPECT_EQ(read.BeforeCall, read.type());
-    EXPECT_EQ(_target, read.arg0());
-    EXPECT_EQ(_level, read.arg1());
-    EXPECT_EQ(_internalformat, read.arg2());
-    EXPECT_EQ(_x, read.arg3());
-    EXPECT_EQ(_y, read.arg4());
-    EXPECT_EQ(_width, read.arg5());
-    EXPECT_EQ(_height, read.arg6());
-    EXPECT_EQ(_border, read.arg7());
-
-    EXPECT_TRUE(read.has_data());
-    EXPECT_EQ(read.ReferencedImage, read.data_type());
-    EXPECT_EQ(GL_RGBA, read.pixel_format());
-    EXPECT_EQ(GL_UNSIGNED_BYTE, read.pixel_type());
-    uint32_t dataLen = 0;
-    unsigned char * const data = dbg->Decompress(read.data().data(),
-                                 read.data().length(), &dataLen);
-    ASSERT_EQ(sizeof(_pixels), dataLen);
-    for (unsigned i = 0; i < sizeof(_pixels) / sizeof(*_pixels); i++)
-        EXPECT_EQ(_pixels[i], ((const int *)data)[i]) << "xor with 0 ref is identity";
-    free(data);
-
-    Read(read);
-    EXPECT_EQ(read.glCopyTexImage2D, read.function());
-    EXPECT_EQ(read.AfterCall, read.type());
-
-    CheckNoAvailable();
-}
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 2d31a35..adeaa5b 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -165,6 +165,20 @@
 #undef CALL_GL_API
 #undef CALL_GL_API_RETURN
 
+/*
+ * glGetString() is special because we expose some extensions in the wrapper
+ */
+
+extern "C" const GLubyte * __glGetString(GLenum name);
+
+const GLubyte * glGetString(GLenum name)
+{
+    const GLubyte * ret = egl_get_string_for_current_context(name);
+    if (ret == NULL) {
+        ret = __glGetString(name);
+    }
+    return ret;
+}
 
 /*
  * These GL calls are special because they need to EGL to retrieve some
diff --git a/opengl/libs/GLES_CM/gl_api.in b/opengl/libs/GLES_CM/gl_api.in
index 7f20c4f..c8f6b0c 100644
--- a/opengl/libs/GLES_CM/gl_api.in
+++ b/opengl/libs/GLES_CM/gl_api.in
@@ -262,7 +262,7 @@
 void API_ENTRY(glGetPointerv)(GLenum pname, GLvoid **params) {
     CALL_GL_API(glGetPointerv, pname, params);
 }
-const GLubyte * API_ENTRY(glGetString)(GLenum name) {
+const GLubyte * API_ENTRY(__glGetString)(GLenum name) {
     CALL_GL_API_RETURN(glGetString, name);
 }
 void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) {
diff --git a/opengl/libs/GLES_CM/glext_api.in b/opengl/libs/GLES_CM/glext_api.in
index 5393fa6..268a535 100644
--- a/opengl/libs/GLES_CM/glext_api.in
+++ b/opengl/libs/GLES_CM/glext_api.in
@@ -280,15 +280,57 @@
 GLboolean API_ENTRY(glIsVertexArrayOES)(GLuint array) {
     CALL_GL_API_RETURN(glIsVertexArrayOES, array);
 }
+void API_ENTRY(glRenderbufferStorageMultisampleAPPLE)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glRenderbufferStorageMultisampleAPPLE, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glResolveMultisampleFramebufferAPPLE)(void) {
+    CALL_GL_API(glResolveMultisampleFramebufferAPPLE);
+}
 void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) {
     CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments);
 }
+void API_ENTRY(glRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glRenderbufferStorageMultisampleEXT, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glFramebufferTexture2DMultisampleEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) {
+    CALL_GL_API(glFramebufferTexture2DMultisampleEXT, target, attachment, textarget, texture, level, samples);
+}
 void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) {
     CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount);
 }
 void API_ENTRY(glMultiDrawElementsEXT)(GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) {
     CALL_GL_API(glMultiDrawElementsEXT, mode, count, type, indices, primcount);
 }
+GLenum API_ENTRY(glGetGraphicsResetStatusEXT)(void) {
+    CALL_GL_API_RETURN(glGetGraphicsResetStatusEXT);
+}
+void API_ENTRY(glReadnPixelsEXT)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) {
+    CALL_GL_API(glReadnPixelsEXT, x, y, width, height, format, type, bufSize, data);
+}
+void API_ENTRY(glGetnUniformfvEXT)(GLuint program, GLint location, GLsizei bufSize, float *params) {
+    CALL_GL_API(glGetnUniformfvEXT, program, location, bufSize, params);
+}
+void API_ENTRY(glGetnUniformivEXT)(GLuint program, GLint location, GLsizei bufSize, GLint *params) {
+    CALL_GL_API(glGetnUniformivEXT, program, location, bufSize, params);
+}
+void API_ENTRY(glTexStorage1DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+    CALL_GL_API(glTexStorage1DEXT, target, levels, internalformat, width);
+}
+void API_ENTRY(glTexStorage2DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glTexStorage2DEXT, target, levels, internalformat, width, height);
+}
+void API_ENTRY(glTexStorage3DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+    CALL_GL_API(glTexStorage3DEXT, target, levels, internalformat, width, height, depth);
+}
+void API_ENTRY(glTextureStorage1DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+    CALL_GL_API(glTextureStorage1DEXT, texture, target, levels, internalformat, width);
+}
+void API_ENTRY(glTextureStorage2DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+    CALL_GL_API(glTextureStorage2DEXT, texture, target, levels, internalformat, width, height);
+}
+void API_ENTRY(glTextureStorage3DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+    CALL_GL_API(glTextureStorage3DEXT, texture, target, levels, internalformat, width, height, depth);
+}
 void API_ENTRY(glClipPlanefIMG)(GLenum p, const GLfloat *eqn) {
     CALL_GL_API(glClipPlanefIMG, p, eqn);
 }
diff --git a/opengl/libs/GLES_trace/gltrace.proto b/opengl/libs/GLES_trace/gltrace.proto
index 7dde69f..11cf24f 100644
--- a/opengl/libs/GLES_trace/gltrace.proto
+++ b/opengl/libs/GLES_trace/gltrace.proto
@@ -400,6 +400,68 @@
         glViewport = 374;
         glWeightPointerOES = 375;
 
+        glActiveShaderProgramEXT = 502;
+        glAlphaFuncQCOM = 503;
+        glBeginQueryEXT = 504;
+        glBindProgramPipelineEXT = 505;
+        glBlitFramebufferANGLE = 506;
+        glCreateShaderProgramvEXT = 507;
+        glDeleteProgramPipelinesEXT = 508;
+        glDeleteQueriesEXT = 509;
+        glDrawBuffersNV = 510;
+        glEndQueryEXT = 511;
+        glFramebufferTexture2DMultisampleEXT = 512;
+        glGenProgramPipelinesEXT = 513;
+        glGenQueriesEXT = 514;
+        glGetGraphicsResetStatusEXT = 515;
+        glGetObjectLabelEXT = 516;
+        glGetProgramPipelineInfoLogEXT = 517;
+        glGetProgramPipelineivEXT = 518;
+        glGetQueryObjectuivEXT = 519;
+        glGetQueryivEXT = 520;
+        glGetnUniformfvEXT = 521;
+        glGetnUniformivEXT = 521;
+        glInsertEventMarkerEXT = 522;
+        glIsProgramPipelineEXT = 523;
+        glIsQueryEXT = 524;
+        glLabelObjectEXT = 525;
+        glPopGroupMarkerEXT = 526;
+        glProgramParameteriEXT = 527;
+        glProgramUniform1fEXT = 528;
+        glProgramUniform1fvEXT = 529;
+        glProgramUniform1iEXT = 530;
+        glProgramUniform1ivEXT = 531;
+        glProgramUniform2fEXT = 532;
+        glProgramUniform2fvEXT = 533;
+        glProgramUniform2iEXT = 534;
+        glProgramUniform2ivEXT = 535;
+        glProgramUniform3fEXT = 536;
+        glProgramUniform3fvEXT = 537;
+        glProgramUniform3iEXT = 538;
+        glProgramUniform3ivEXT = 539;
+        glProgramUniform4fEXT = 540;
+        glProgramUniform4fvEXT = 541;
+        glProgramUniform4iEXT = 542;
+        glProgramUniform4ivEXT = 543;
+        glProgramUniformMatrix2fvEXT = 544;
+        glProgramUniformMatrix3fvEXT = 545;
+        glProgramUniformMatrix4fvEXT = 546;
+        glPushGroupMarkerEXT = 547;
+        glReadBufferNV = 548;
+        glReadnPixelsEXT = 549;
+        glRenderbufferStorageMultisampleANGLE = 550;
+        glRenderbufferStorageMultisampleAPPLE = 551;
+        glRenderbufferStorageMultisampleEXT = 552;
+        glResolveMultisampleFramebufferAPPLE = 553;
+        glTexStorage1DEXT = 554;
+        glTexStorage2DEXT = 555;
+        glTexStorage3DEXT = 556;
+        glTextureStorage1DEXT = 557;
+        glTextureStorage2DEXT = 558;
+        glTextureStorage3DEXT = 559;
+        glUseProgramStagesEXT = 560;
+        glValidateProgramPipelineEXT = 561;
+
         eglGetDisplay = 2000;
         eglInitialize = 2001;
         eglTerminate = 2002;
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.cpp b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
index 9a90603..bb9d4a7 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
@@ -419,6 +419,66 @@
     case 373:
     case 374:
     case 375:
+    case 502:
+    case 503:
+    case 504:
+    case 505:
+    case 506:
+    case 507:
+    case 508:
+    case 509:
+    case 510:
+    case 511:
+    case 512:
+    case 513:
+    case 514:
+    case 515:
+    case 516:
+    case 517:
+    case 518:
+    case 519:
+    case 520:
+    case 521:
+    case 522:
+    case 523:
+    case 524:
+    case 525:
+    case 526:
+    case 527:
+    case 528:
+    case 529:
+    case 530:
+    case 531:
+    case 532:
+    case 533:
+    case 534:
+    case 535:
+    case 536:
+    case 537:
+    case 538:
+    case 539:
+    case 540:
+    case 541:
+    case 542:
+    case 543:
+    case 544:
+    case 545:
+    case 546:
+    case 547:
+    case 548:
+    case 549:
+    case 550:
+    case 551:
+    case 552:
+    case 553:
+    case 554:
+    case 555:
+    case 556:
+    case 557:
+    case 558:
+    case 559:
+    case 560:
+    case 561:
     case 2000:
     case 2001:
     case 2002:
@@ -850,6 +910,67 @@
 const GLMessage_Function GLMessage::glVertexPointer;
 const GLMessage_Function GLMessage::glViewport;
 const GLMessage_Function GLMessage::glWeightPointerOES;
+const GLMessage_Function GLMessage::glActiveShaderProgramEXT;
+const GLMessage_Function GLMessage::glAlphaFuncQCOM;
+const GLMessage_Function GLMessage::glBeginQueryEXT;
+const GLMessage_Function GLMessage::glBindProgramPipelineEXT;
+const GLMessage_Function GLMessage::glBlitFramebufferANGLE;
+const GLMessage_Function GLMessage::glCreateShaderProgramvEXT;
+const GLMessage_Function GLMessage::glDeleteProgramPipelinesEXT;
+const GLMessage_Function GLMessage::glDeleteQueriesEXT;
+const GLMessage_Function GLMessage::glDrawBuffersNV;
+const GLMessage_Function GLMessage::glEndQueryEXT;
+const GLMessage_Function GLMessage::glFramebufferTexture2DMultisampleEXT;
+const GLMessage_Function GLMessage::glGenProgramPipelinesEXT;
+const GLMessage_Function GLMessage::glGenQueriesEXT;
+const GLMessage_Function GLMessage::glGetGraphicsResetStatusEXT;
+const GLMessage_Function GLMessage::glGetObjectLabelEXT;
+const GLMessage_Function GLMessage::glGetProgramPipelineInfoLogEXT;
+const GLMessage_Function GLMessage::glGetProgramPipelineivEXT;
+const GLMessage_Function GLMessage::glGetQueryObjectuivEXT;
+const GLMessage_Function GLMessage::glGetQueryivEXT;
+const GLMessage_Function GLMessage::glGetnUniformfvEXT;
+const GLMessage_Function GLMessage::glGetnUniformivEXT;
+const GLMessage_Function GLMessage::glInsertEventMarkerEXT;
+const GLMessage_Function GLMessage::glIsProgramPipelineEXT;
+const GLMessage_Function GLMessage::glIsQueryEXT;
+const GLMessage_Function GLMessage::glLabelObjectEXT;
+const GLMessage_Function GLMessage::glPopGroupMarkerEXT;
+const GLMessage_Function GLMessage::glProgramParameteriEXT;
+const GLMessage_Function GLMessage::glProgramUniform1fEXT;
+const GLMessage_Function GLMessage::glProgramUniform1fvEXT;
+const GLMessage_Function GLMessage::glProgramUniform1iEXT;
+const GLMessage_Function GLMessage::glProgramUniform1ivEXT;
+const GLMessage_Function GLMessage::glProgramUniform2fEXT;
+const GLMessage_Function GLMessage::glProgramUniform2fvEXT;
+const GLMessage_Function GLMessage::glProgramUniform2iEXT;
+const GLMessage_Function GLMessage::glProgramUniform2ivEXT;
+const GLMessage_Function GLMessage::glProgramUniform3fEXT;
+const GLMessage_Function GLMessage::glProgramUniform3fvEXT;
+const GLMessage_Function GLMessage::glProgramUniform3iEXT;
+const GLMessage_Function GLMessage::glProgramUniform3ivEXT;
+const GLMessage_Function GLMessage::glProgramUniform4fEXT;
+const GLMessage_Function GLMessage::glProgramUniform4fvEXT;
+const GLMessage_Function GLMessage::glProgramUniform4iEXT;
+const GLMessage_Function GLMessage::glProgramUniform4ivEXT;
+const GLMessage_Function GLMessage::glProgramUniformMatrix2fvEXT;
+const GLMessage_Function GLMessage::glProgramUniformMatrix3fvEXT;
+const GLMessage_Function GLMessage::glProgramUniformMatrix4fvEXT;
+const GLMessage_Function GLMessage::glPushGroupMarkerEXT;
+const GLMessage_Function GLMessage::glReadBufferNV;
+const GLMessage_Function GLMessage::glReadnPixelsEXT;
+const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleANGLE;
+const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleAPPLE;
+const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleEXT;
+const GLMessage_Function GLMessage::glResolveMultisampleFramebufferAPPLE;
+const GLMessage_Function GLMessage::glTexStorage1DEXT;
+const GLMessage_Function GLMessage::glTexStorage2DEXT;
+const GLMessage_Function GLMessage::glTexStorage3DEXT;
+const GLMessage_Function GLMessage::glTextureStorage1DEXT;
+const GLMessage_Function GLMessage::glTextureStorage2DEXT;
+const GLMessage_Function GLMessage::glTextureStorage3DEXT;
+const GLMessage_Function GLMessage::glUseProgramStagesEXT;
+const GLMessage_Function GLMessage::glValidateProgramPipelineEXT;
 const GLMessage_Function GLMessage::eglGetDisplay;
 const GLMessage_Function GLMessage::eglInitialize;
 const GLMessage_Function GLMessage::eglTerminate;
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.h b/opengl/libs/GLES_trace/src/gltrace.pb.h
index 5a7a16f..e3b8990 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.h
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.h
@@ -427,6 +427,67 @@
   GLMessage_Function_glVertexPointer = 373,
   GLMessage_Function_glViewport = 374,
   GLMessage_Function_glWeightPointerOES = 375,
+  GLMessage_Function_glActiveShaderProgramEXT = 502,
+  GLMessage_Function_glAlphaFuncQCOM = 503,
+  GLMessage_Function_glBeginQueryEXT = 504,
+  GLMessage_Function_glBindProgramPipelineEXT = 505,
+  GLMessage_Function_glBlitFramebufferANGLE = 506,
+  GLMessage_Function_glCreateShaderProgramvEXT = 507,
+  GLMessage_Function_glDeleteProgramPipelinesEXT = 508,
+  GLMessage_Function_glDeleteQueriesEXT = 509,
+  GLMessage_Function_glDrawBuffersNV = 510,
+  GLMessage_Function_glEndQueryEXT = 511,
+  GLMessage_Function_glFramebufferTexture2DMultisampleEXT = 512,
+  GLMessage_Function_glGenProgramPipelinesEXT = 513,
+  GLMessage_Function_glGenQueriesEXT = 514,
+  GLMessage_Function_glGetGraphicsResetStatusEXT = 515,
+  GLMessage_Function_glGetObjectLabelEXT = 516,
+  GLMessage_Function_glGetProgramPipelineInfoLogEXT = 517,
+  GLMessage_Function_glGetProgramPipelineivEXT = 518,
+  GLMessage_Function_glGetQueryObjectuivEXT = 519,
+  GLMessage_Function_glGetQueryivEXT = 520,
+  GLMessage_Function_glGetnUniformfvEXT = 521,
+  GLMessage_Function_glGetnUniformivEXT = 521,
+  GLMessage_Function_glInsertEventMarkerEXT = 522,
+  GLMessage_Function_glIsProgramPipelineEXT = 523,
+  GLMessage_Function_glIsQueryEXT = 524,
+  GLMessage_Function_glLabelObjectEXT = 525,
+  GLMessage_Function_glPopGroupMarkerEXT = 526,
+  GLMessage_Function_glProgramParameteriEXT = 527,
+  GLMessage_Function_glProgramUniform1fEXT = 528,
+  GLMessage_Function_glProgramUniform1fvEXT = 529,
+  GLMessage_Function_glProgramUniform1iEXT = 530,
+  GLMessage_Function_glProgramUniform1ivEXT = 531,
+  GLMessage_Function_glProgramUniform2fEXT = 532,
+  GLMessage_Function_glProgramUniform2fvEXT = 533,
+  GLMessage_Function_glProgramUniform2iEXT = 534,
+  GLMessage_Function_glProgramUniform2ivEXT = 535,
+  GLMessage_Function_glProgramUniform3fEXT = 536,
+  GLMessage_Function_glProgramUniform3fvEXT = 537,
+  GLMessage_Function_glProgramUniform3iEXT = 538,
+  GLMessage_Function_glProgramUniform3ivEXT = 539,
+  GLMessage_Function_glProgramUniform4fEXT = 540,
+  GLMessage_Function_glProgramUniform4fvEXT = 541,
+  GLMessage_Function_glProgramUniform4iEXT = 542,
+  GLMessage_Function_glProgramUniform4ivEXT = 543,
+  GLMessage_Function_glProgramUniformMatrix2fvEXT = 544,
+  GLMessage_Function_glProgramUniformMatrix3fvEXT = 545,
+  GLMessage_Function_glProgramUniformMatrix4fvEXT = 546,
+  GLMessage_Function_glPushGroupMarkerEXT = 547,
+  GLMessage_Function_glReadBufferNV = 548,
+  GLMessage_Function_glReadnPixelsEXT = 549,
+  GLMessage_Function_glRenderbufferStorageMultisampleANGLE = 550,
+  GLMessage_Function_glRenderbufferStorageMultisampleAPPLE = 551,
+  GLMessage_Function_glRenderbufferStorageMultisampleEXT = 552,
+  GLMessage_Function_glResolveMultisampleFramebufferAPPLE = 553,
+  GLMessage_Function_glTexStorage1DEXT = 554,
+  GLMessage_Function_glTexStorage2DEXT = 555,
+  GLMessage_Function_glTexStorage3DEXT = 556,
+  GLMessage_Function_glTextureStorage1DEXT = 557,
+  GLMessage_Function_glTextureStorage2DEXT = 558,
+  GLMessage_Function_glTextureStorage3DEXT = 559,
+  GLMessage_Function_glUseProgramStagesEXT = 560,
+  GLMessage_Function_glValidateProgramPipelineEXT = 561,
   GLMessage_Function_eglGetDisplay = 2000,
   GLMessage_Function_eglInitialize = 2001,
   GLMessage_Function_eglTerminate = 2002,
@@ -1182,6 +1243,67 @@
   static const Function glVertexPointer = GLMessage_Function_glVertexPointer;
   static const Function glViewport = GLMessage_Function_glViewport;
   static const Function glWeightPointerOES = GLMessage_Function_glWeightPointerOES;
+  static const Function glActiveShaderProgramEXT = GLMessage_Function_glActiveShaderProgramEXT;
+  static const Function glAlphaFuncQCOM = GLMessage_Function_glAlphaFuncQCOM;
+  static const Function glBeginQueryEXT = GLMessage_Function_glBeginQueryEXT;
+  static const Function glBindProgramPipelineEXT = GLMessage_Function_glBindProgramPipelineEXT;
+  static const Function glBlitFramebufferANGLE = GLMessage_Function_glBlitFramebufferANGLE;
+  static const Function glCreateShaderProgramvEXT = GLMessage_Function_glCreateShaderProgramvEXT;
+  static const Function glDeleteProgramPipelinesEXT = GLMessage_Function_glDeleteProgramPipelinesEXT;
+  static const Function glDeleteQueriesEXT = GLMessage_Function_glDeleteQueriesEXT;
+  static const Function glDrawBuffersNV = GLMessage_Function_glDrawBuffersNV;
+  static const Function glEndQueryEXT = GLMessage_Function_glEndQueryEXT;
+  static const Function glFramebufferTexture2DMultisampleEXT = GLMessage_Function_glFramebufferTexture2DMultisampleEXT;
+  static const Function glGenProgramPipelinesEXT = GLMessage_Function_glGenProgramPipelinesEXT;
+  static const Function glGenQueriesEXT = GLMessage_Function_glGenQueriesEXT;
+  static const Function glGetGraphicsResetStatusEXT = GLMessage_Function_glGetGraphicsResetStatusEXT;
+  static const Function glGetObjectLabelEXT = GLMessage_Function_glGetObjectLabelEXT;
+  static const Function glGetProgramPipelineInfoLogEXT = GLMessage_Function_glGetProgramPipelineInfoLogEXT;
+  static const Function glGetProgramPipelineivEXT = GLMessage_Function_glGetProgramPipelineivEXT;
+  static const Function glGetQueryObjectuivEXT = GLMessage_Function_glGetQueryObjectuivEXT;
+  static const Function glGetQueryivEXT = GLMessage_Function_glGetQueryivEXT;
+  static const Function glGetnUniformfvEXT = GLMessage_Function_glGetnUniformfvEXT;
+  static const Function glGetnUniformivEXT = GLMessage_Function_glGetnUniformivEXT;
+  static const Function glInsertEventMarkerEXT = GLMessage_Function_glInsertEventMarkerEXT;
+  static const Function glIsProgramPipelineEXT = GLMessage_Function_glIsProgramPipelineEXT;
+  static const Function glIsQueryEXT = GLMessage_Function_glIsQueryEXT;
+  static const Function glLabelObjectEXT = GLMessage_Function_glLabelObjectEXT;
+  static const Function glPopGroupMarkerEXT = GLMessage_Function_glPopGroupMarkerEXT;
+  static const Function glProgramParameteriEXT = GLMessage_Function_glProgramParameteriEXT;
+  static const Function glProgramUniform1fEXT = GLMessage_Function_glProgramUniform1fEXT;
+  static const Function glProgramUniform1fvEXT = GLMessage_Function_glProgramUniform1fvEXT;
+  static const Function glProgramUniform1iEXT = GLMessage_Function_glProgramUniform1iEXT;
+  static const Function glProgramUniform1ivEXT = GLMessage_Function_glProgramUniform1ivEXT;
+  static const Function glProgramUniform2fEXT = GLMessage_Function_glProgramUniform2fEXT;
+  static const Function glProgramUniform2fvEXT = GLMessage_Function_glProgramUniform2fvEXT;
+  static const Function glProgramUniform2iEXT = GLMessage_Function_glProgramUniform2iEXT;
+  static const Function glProgramUniform2ivEXT = GLMessage_Function_glProgramUniform2ivEXT;
+  static const Function glProgramUniform3fEXT = GLMessage_Function_glProgramUniform3fEXT;
+  static const Function glProgramUniform3fvEXT = GLMessage_Function_glProgramUniform3fvEXT;
+  static const Function glProgramUniform3iEXT = GLMessage_Function_glProgramUniform3iEXT;
+  static const Function glProgramUniform3ivEXT = GLMessage_Function_glProgramUniform3ivEXT;
+  static const Function glProgramUniform4fEXT = GLMessage_Function_glProgramUniform4fEXT;
+  static const Function glProgramUniform4fvEXT = GLMessage_Function_glProgramUniform4fvEXT;
+  static const Function glProgramUniform4iEXT = GLMessage_Function_glProgramUniform4iEXT;
+  static const Function glProgramUniform4ivEXT = GLMessage_Function_glProgramUniform4ivEXT;
+  static const Function glProgramUniformMatrix2fvEXT = GLMessage_Function_glProgramUniformMatrix2fvEXT;
+  static const Function glProgramUniformMatrix3fvEXT = GLMessage_Function_glProgramUniformMatrix3fvEXT;
+  static const Function glProgramUniformMatrix4fvEXT = GLMessage_Function_glProgramUniformMatrix4fvEXT;
+  static const Function glPushGroupMarkerEXT = GLMessage_Function_glPushGroupMarkerEXT;
+  static const Function glReadBufferNV = GLMessage_Function_glReadBufferNV;
+  static const Function glReadnPixelsEXT = GLMessage_Function_glReadnPixelsEXT;
+  static const Function glRenderbufferStorageMultisampleANGLE = GLMessage_Function_glRenderbufferStorageMultisampleANGLE;
+  static const Function glRenderbufferStorageMultisampleAPPLE = GLMessage_Function_glRenderbufferStorageMultisampleAPPLE;
+  static const Function glRenderbufferStorageMultisampleEXT = GLMessage_Function_glRenderbufferStorageMultisampleEXT;
+  static const Function glResolveMultisampleFramebufferAPPLE = GLMessage_Function_glResolveMultisampleFramebufferAPPLE;
+  static const Function glTexStorage1DEXT = GLMessage_Function_glTexStorage1DEXT;
+  static const Function glTexStorage2DEXT = GLMessage_Function_glTexStorage2DEXT;
+  static const Function glTexStorage3DEXT = GLMessage_Function_glTexStorage3DEXT;
+  static const Function glTextureStorage1DEXT = GLMessage_Function_glTextureStorage1DEXT;
+  static const Function glTextureStorage2DEXT = GLMessage_Function_glTextureStorage2DEXT;
+  static const Function glTextureStorage3DEXT = GLMessage_Function_glTextureStorage3DEXT;
+  static const Function glUseProgramStagesEXT = GLMessage_Function_glUseProgramStagesEXT;
+  static const Function glValidateProgramPipelineEXT = GLMessage_Function_glValidateProgramPipelineEXT;
   static const Function eglGetDisplay = GLMessage_Function_eglGetDisplay;
   static const Function eglInitialize = GLMessage_Function_eglInitialize;
   static const Function eglTerminate = GLMessage_Function_eglTerminate;
diff --git a/opengl/libs/GLES_trace/src/gltrace_api.cpp b/opengl/libs/GLES_trace/src/gltrace_api.cpp
index c8e820d..a2366ac 100644
--- a/opengl/libs/GLES_trace/src/gltrace_api.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_api.cpp
@@ -5809,6 +5809,339 @@
     glContext->traceGLMessage(&glmsg);
 }
 
+void GLTrace_glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glBlitFramebufferANGLE);
+
+    // copy argument srcX0
+    GLMessage_DataType *arg_srcX0 = glmsg.add_args();
+    arg_srcX0->set_isarray(false);
+    arg_srcX0->set_type(GLMessage::DataType::INT);
+    arg_srcX0->add_intvalue(srcX0);
+
+    // copy argument srcY0
+    GLMessage_DataType *arg_srcY0 = glmsg.add_args();
+    arg_srcY0->set_isarray(false);
+    arg_srcY0->set_type(GLMessage::DataType::INT);
+    arg_srcY0->add_intvalue(srcY0);
+
+    // copy argument srcX1
+    GLMessage_DataType *arg_srcX1 = glmsg.add_args();
+    arg_srcX1->set_isarray(false);
+    arg_srcX1->set_type(GLMessage::DataType::INT);
+    arg_srcX1->add_intvalue(srcX1);
+
+    // copy argument srcY1
+    GLMessage_DataType *arg_srcY1 = glmsg.add_args();
+    arg_srcY1->set_isarray(false);
+    arg_srcY1->set_type(GLMessage::DataType::INT);
+    arg_srcY1->add_intvalue(srcY1);
+
+    // copy argument dstX0
+    GLMessage_DataType *arg_dstX0 = glmsg.add_args();
+    arg_dstX0->set_isarray(false);
+    arg_dstX0->set_type(GLMessage::DataType::INT);
+    arg_dstX0->add_intvalue(dstX0);
+
+    // copy argument dstY0
+    GLMessage_DataType *arg_dstY0 = glmsg.add_args();
+    arg_dstY0->set_isarray(false);
+    arg_dstY0->set_type(GLMessage::DataType::INT);
+    arg_dstY0->add_intvalue(dstY0);
+
+    // copy argument dstX1
+    GLMessage_DataType *arg_dstX1 = glmsg.add_args();
+    arg_dstX1->set_isarray(false);
+    arg_dstX1->set_type(GLMessage::DataType::INT);
+    arg_dstX1->add_intvalue(dstX1);
+
+    // copy argument dstY1
+    GLMessage_DataType *arg_dstY1 = glmsg.add_args();
+    arg_dstY1->set_isarray(false);
+    arg_dstY1->set_type(GLMessage::DataType::INT);
+    arg_dstY1->add_intvalue(dstY1);
+
+    // copy argument mask
+    GLMessage_DataType *arg_mask = glmsg.add_args();
+    arg_mask->set_isarray(false);
+    arg_mask->set_type(GLMessage::DataType::INT);
+    arg_mask->add_intvalue(mask);
+
+    // copy argument filter
+    GLMessage_DataType *arg_filter = glmsg.add_args();
+    arg_filter->set_isarray(false);
+    arg_filter->set_type(GLMessage::DataType::ENUM);
+    arg_filter->add_intvalue((int)filter);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glBlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glRenderbufferStorageMultisampleANGLE);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument samples
+    GLMessage_DataType *arg_samples = glmsg.add_args();
+    arg_samples->set_isarray(false);
+    arg_samples->set_type(GLMessage::DataType::INT);
+    arg_samples->add_intvalue(samples);
+
+    // copy argument internalformat
+    GLMessage_DataType *arg_internalformat = glmsg.add_args();
+    arg_internalformat->set_isarray(false);
+    arg_internalformat->set_type(GLMessage::DataType::ENUM);
+    arg_internalformat->add_intvalue((int)internalformat);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // copy argument height
+    GLMessage_DataType *arg_height = glmsg.add_args();
+    arg_height->set_isarray(false);
+    arg_height->set_type(GLMessage::DataType::INT);
+    arg_height->add_intvalue(height);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glRenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glRenderbufferStorageMultisampleAPPLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glRenderbufferStorageMultisampleAPPLE);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument samples
+    GLMessage_DataType *arg_samples = glmsg.add_args();
+    arg_samples->set_isarray(false);
+    arg_samples->set_type(GLMessage::DataType::INT);
+    arg_samples->add_intvalue(samples);
+
+    // copy argument internalformat
+    GLMessage_DataType *arg_internalformat = glmsg.add_args();
+    arg_internalformat->set_isarray(false);
+    arg_internalformat->set_type(GLMessage::DataType::ENUM);
+    arg_internalformat->add_intvalue((int)internalformat);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // copy argument height
+    GLMessage_DataType *arg_height = glmsg.add_args();
+    arg_height->set_isarray(false);
+    arg_height->set_type(GLMessage::DataType::INT);
+    arg_height->add_intvalue(height);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glRenderbufferStorageMultisampleAPPLE(target, samples, internalformat, width, height);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glResolveMultisampleFramebufferAPPLE(void) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glResolveMultisampleFramebufferAPPLE);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glResolveMultisampleFramebufferAPPLE();
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glLabelObjectEXT(GLenum type, GLuint object, GLsizei length, const GLchar *label) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glLabelObjectEXT);
+
+    // copy argument type
+    GLMessage_DataType *arg_type = glmsg.add_args();
+    arg_type->set_isarray(false);
+    arg_type->set_type(GLMessage::DataType::ENUM);
+    arg_type->add_intvalue((int)type);
+
+    // copy argument object
+    GLMessage_DataType *arg_object = glmsg.add_args();
+    arg_object->set_isarray(false);
+    arg_object->set_type(GLMessage::DataType::INT);
+    arg_object->add_intvalue(object);
+
+    // copy argument length
+    GLMessage_DataType *arg_length = glmsg.add_args();
+    arg_length->set_isarray(false);
+    arg_length->set_type(GLMessage::DataType::INT);
+    arg_length->add_intvalue(length);
+
+    // copy argument label
+    GLMessage_DataType *arg_label = glmsg.add_args();
+    arg_label->set_isarray(false);
+    arg_label->set_type(GLMessage::DataType::INT);
+    arg_label->add_intvalue((int)label);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glLabelObjectEXT(type, object, length, label);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetObjectLabelEXT(GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGetObjectLabelEXT);
+
+    // copy argument type
+    GLMessage_DataType *arg_type = glmsg.add_args();
+    arg_type->set_isarray(false);
+    arg_type->set_type(GLMessage::DataType::ENUM);
+    arg_type->add_intvalue((int)type);
+
+    // copy argument object
+    GLMessage_DataType *arg_object = glmsg.add_args();
+    arg_object->set_isarray(false);
+    arg_object->set_type(GLMessage::DataType::INT);
+    arg_object->add_intvalue(object);
+
+    // copy argument bufSize
+    GLMessage_DataType *arg_bufSize = glmsg.add_args();
+    arg_bufSize->set_isarray(false);
+    arg_bufSize->set_type(GLMessage::DataType::INT);
+    arg_bufSize->add_intvalue(bufSize);
+
+    // copy argument length
+    GLMessage_DataType *arg_length = glmsg.add_args();
+    arg_length->set_isarray(false);
+    arg_length->set_type(GLMessage::DataType::INT);
+    arg_length->add_intvalue((int)length);
+
+    // copy argument label
+    GLMessage_DataType *arg_label = glmsg.add_args();
+    arg_label->set_isarray(false);
+    arg_label->set_type(GLMessage::DataType::INT);
+    arg_label->add_intvalue((int)label);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glGetObjectLabelEXT(type, object, bufSize, length, label);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glInsertEventMarkerEXT);
+
+    // copy argument length
+    GLMessage_DataType *arg_length = glmsg.add_args();
+    arg_length->set_isarray(false);
+    arg_length->set_type(GLMessage::DataType::INT);
+    arg_length->add_intvalue(length);
+
+    // copy argument marker
+    GLMessage_DataType *arg_marker = glmsg.add_args();
+    arg_marker->set_isarray(false);
+    arg_marker->set_type(GLMessage::DataType::INT);
+    arg_marker->add_intvalue((int)marker);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glInsertEventMarkerEXT(length, marker);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glPushGroupMarkerEXT);
+
+    // copy argument length
+    GLMessage_DataType *arg_length = glmsg.add_args();
+    arg_length->set_isarray(false);
+    arg_length->set_type(GLMessage::DataType::INT);
+    arg_length->add_intvalue(length);
+
+    // copy argument marker
+    GLMessage_DataType *arg_marker = glmsg.add_args();
+    arg_marker->set_isarray(false);
+    arg_marker->set_type(GLMessage::DataType::INT);
+    arg_marker->add_intvalue((int)marker);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glPushGroupMarkerEXT(length, marker);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glPopGroupMarkerEXT(void) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glPopGroupMarkerEXT);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glPopGroupMarkerEXT();
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
 void GLTrace_glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {
     GLMessage glmsg;
     GLTraceContext *glContext = getGLTraceContext();
@@ -5842,6 +6175,102 @@
     glContext->traceGLMessage(&glmsg);
 }
 
+void GLTrace_glRenderbufferStorageMultisampleEXT(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glRenderbufferStorageMultisampleEXT);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument samples
+    GLMessage_DataType *arg_samples = glmsg.add_args();
+    arg_samples->set_isarray(false);
+    arg_samples->set_type(GLMessage::DataType::INT);
+    arg_samples->add_intvalue(samples);
+
+    // copy argument internalformat
+    GLMessage_DataType *arg_internalformat = glmsg.add_args();
+    arg_internalformat->set_isarray(false);
+    arg_internalformat->set_type(GLMessage::DataType::ENUM);
+    arg_internalformat->add_intvalue((int)internalformat);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // copy argument height
+    GLMessage_DataType *arg_height = glmsg.add_args();
+    arg_height->set_isarray(false);
+    arg_height->set_type(GLMessage::DataType::INT);
+    arg_height->add_intvalue(height);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glFramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glFramebufferTexture2DMultisampleEXT);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument attachment
+    GLMessage_DataType *arg_attachment = glmsg.add_args();
+    arg_attachment->set_isarray(false);
+    arg_attachment->set_type(GLMessage::DataType::ENUM);
+    arg_attachment->add_intvalue((int)attachment);
+
+    // copy argument textarget
+    GLMessage_DataType *arg_textarget = glmsg.add_args();
+    arg_textarget->set_isarray(false);
+    arg_textarget->set_type(GLMessage::DataType::ENUM);
+    arg_textarget->add_intvalue((int)textarget);
+
+    // copy argument texture
+    GLMessage_DataType *arg_texture = glmsg.add_args();
+    arg_texture->set_isarray(false);
+    arg_texture->set_type(GLMessage::DataType::INT);
+    arg_texture->add_intvalue(texture);
+
+    // copy argument level
+    GLMessage_DataType *arg_level = glmsg.add_args();
+    arg_level->set_isarray(false);
+    arg_level->set_type(GLMessage::DataType::INT);
+    arg_level->add_intvalue(level);
+
+    // copy argument samples
+    GLMessage_DataType *arg_samples = glmsg.add_args();
+    arg_samples->set_isarray(false);
+    arg_samples->set_type(GLMessage::DataType::INT);
+    arg_samples->add_intvalue(samples);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glFramebufferTexture2DMultisampleEXT(target, attachment, textarget, texture, level, samples);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
 void GLTrace_glMultiDrawArraysEXT(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) {
     GLMessage glmsg;
     GLTraceContext *glContext = getGLTraceContext();
@@ -5926,6 +6355,1769 @@
     glContext->traceGLMessage(&glmsg);
 }
 
+void GLTrace_glGenQueriesEXT(GLsizei n, GLuint *ids) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGenQueriesEXT);
+
+    // copy argument n
+    GLMessage_DataType *arg_n = glmsg.add_args();
+    arg_n->set_isarray(false);
+    arg_n->set_type(GLMessage::DataType::INT);
+    arg_n->add_intvalue(n);
+
+    // copy argument ids
+    GLMessage_DataType *arg_ids = glmsg.add_args();
+    arg_ids->set_isarray(false);
+    arg_ids->set_type(GLMessage::DataType::INT);
+    arg_ids->add_intvalue((int)ids);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glGenQueriesEXT(n, ids);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glDeleteQueriesEXT(GLsizei n, const GLuint *ids) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glDeleteQueriesEXT);
+
+    // copy argument n
+    GLMessage_DataType *arg_n = glmsg.add_args();
+    arg_n->set_isarray(false);
+    arg_n->set_type(GLMessage::DataType::INT);
+    arg_n->add_intvalue(n);
+
+    // copy argument ids
+    GLMessage_DataType *arg_ids = glmsg.add_args();
+    arg_ids->set_isarray(false);
+    arg_ids->set_type(GLMessage::DataType::INT);
+    arg_ids->add_intvalue((int)ids);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glDeleteQueriesEXT(n, ids);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+GLboolean GLTrace_glIsQueryEXT(GLuint id) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glIsQueryEXT);
+
+    // copy argument id
+    GLMessage_DataType *arg_id = glmsg.add_args();
+    arg_id->set_isarray(false);
+    arg_id->set_type(GLMessage::DataType::INT);
+    arg_id->add_intvalue(id);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    GLboolean retValue = glContext->hooks->gl.glIsQueryEXT(id);
+    nsecs_t end_time = systemTime();
+
+    // set return value
+    GLMessage_DataType *rt = glmsg.mutable_returnvalue();
+    rt->set_isarray(false);
+    rt->set_type(GLMessage::DataType::BOOL);
+    rt->add_boolvalue(retValue);
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+
+    return retValue;
+}
+
+void GLTrace_glBeginQueryEXT(GLenum target, GLuint id) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glBeginQueryEXT);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument id
+    GLMessage_DataType *arg_id = glmsg.add_args();
+    arg_id->set_isarray(false);
+    arg_id->set_type(GLMessage::DataType::INT);
+    arg_id->add_intvalue(id);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glBeginQueryEXT(target, id);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glEndQueryEXT(GLenum target) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glEndQueryEXT);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glEndQueryEXT(target);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGetQueryivEXT);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument pname
+    GLMessage_DataType *arg_pname = glmsg.add_args();
+    arg_pname->set_isarray(false);
+    arg_pname->set_type(GLMessage::DataType::ENUM);
+    arg_pname->add_intvalue((int)pname);
+
+    // copy argument params
+    GLMessage_DataType *arg_params = glmsg.add_args();
+    arg_params->set_isarray(false);
+    arg_params->set_type(GLMessage::DataType::INT);
+    arg_params->add_intvalue((int)params);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glGetQueryivEXT(target, pname, params);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGetQueryObjectuivEXT);
+
+    // copy argument id
+    GLMessage_DataType *arg_id = glmsg.add_args();
+    arg_id->set_isarray(false);
+    arg_id->set_type(GLMessage::DataType::INT);
+    arg_id->add_intvalue(id);
+
+    // copy argument pname
+    GLMessage_DataType *arg_pname = glmsg.add_args();
+    arg_pname->set_isarray(false);
+    arg_pname->set_type(GLMessage::DataType::ENUM);
+    arg_pname->add_intvalue((int)pname);
+
+    // copy argument params
+    GLMessage_DataType *arg_params = glmsg.add_args();
+    arg_params->set_isarray(false);
+    arg_params->set_type(GLMessage::DataType::INT);
+    arg_params->add_intvalue((int)params);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glGetQueryObjectuivEXT(id, pname, params);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+GLenum GLTrace_glGetGraphicsResetStatusEXT(void) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGetGraphicsResetStatusEXT);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    GLenum retValue = glContext->hooks->gl.glGetGraphicsResetStatusEXT();
+    nsecs_t end_time = systemTime();
+
+    // set return value
+    GLMessage_DataType *rt = glmsg.mutable_returnvalue();
+    rt->set_isarray(false);
+    rt->set_type(GLMessage::DataType::ENUM);
+    rt->add_intvalue((int)retValue);
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+
+    return retValue;
+}
+
+void GLTrace_glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glReadnPixelsEXT);
+
+    // copy argument x
+    GLMessage_DataType *arg_x = glmsg.add_args();
+    arg_x->set_isarray(false);
+    arg_x->set_type(GLMessage::DataType::INT);
+    arg_x->add_intvalue(x);
+
+    // copy argument y
+    GLMessage_DataType *arg_y = glmsg.add_args();
+    arg_y->set_isarray(false);
+    arg_y->set_type(GLMessage::DataType::INT);
+    arg_y->add_intvalue(y);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // copy argument height
+    GLMessage_DataType *arg_height = glmsg.add_args();
+    arg_height->set_isarray(false);
+    arg_height->set_type(GLMessage::DataType::INT);
+    arg_height->add_intvalue(height);
+
+    // copy argument format
+    GLMessage_DataType *arg_format = glmsg.add_args();
+    arg_format->set_isarray(false);
+    arg_format->set_type(GLMessage::DataType::ENUM);
+    arg_format->add_intvalue((int)format);
+
+    // copy argument type
+    GLMessage_DataType *arg_type = glmsg.add_args();
+    arg_type->set_isarray(false);
+    arg_type->set_type(GLMessage::DataType::ENUM);
+    arg_type->add_intvalue((int)type);
+
+    // copy argument bufSize
+    GLMessage_DataType *arg_bufSize = glmsg.add_args();
+    arg_bufSize->set_isarray(false);
+    arg_bufSize->set_type(GLMessage::DataType::INT);
+    arg_bufSize->add_intvalue(bufSize);
+
+    // copy argument data
+    GLMessage_DataType *arg_data = glmsg.add_args();
+    arg_data->set_isarray(false);
+    arg_data->set_type(GLMessage::DataType::INT);
+    arg_data->add_intvalue((int)data);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glReadnPixelsEXT(x, y, width, height, format, type, bufSize, data);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, float *params) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGetnUniformfvEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument bufSize
+    GLMessage_DataType *arg_bufSize = glmsg.add_args();
+    arg_bufSize->set_isarray(false);
+    arg_bufSize->set_type(GLMessage::DataType::INT);
+    arg_bufSize->add_intvalue(bufSize);
+
+    // copy argument params
+    GLMessage_DataType *arg_params = glmsg.add_args();
+    arg_params->set_isarray(false);
+    arg_params->set_type(GLMessage::DataType::INT);
+    arg_params->add_intvalue((int)params);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glGetnUniformfvEXT(program, location, bufSize, params);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint *params) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGetnUniformivEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument bufSize
+    GLMessage_DataType *arg_bufSize = glmsg.add_args();
+    arg_bufSize->set_isarray(false);
+    arg_bufSize->set_type(GLMessage::DataType::INT);
+    arg_bufSize->add_intvalue(bufSize);
+
+    // copy argument params
+    GLMessage_DataType *arg_params = glmsg.add_args();
+    arg_params->set_isarray(false);
+    arg_params->set_type(GLMessage::DataType::INT);
+    arg_params->add_intvalue((int)params);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glGetnUniformivEXT(program, location, bufSize, params);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glUseProgramStagesEXT(GLuint pipeline, GLbitfield stages, GLuint program) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glUseProgramStagesEXT);
+
+    // copy argument pipeline
+    GLMessage_DataType *arg_pipeline = glmsg.add_args();
+    arg_pipeline->set_isarray(false);
+    arg_pipeline->set_type(GLMessage::DataType::INT);
+    arg_pipeline->add_intvalue(pipeline);
+
+    // copy argument stages
+    GLMessage_DataType *arg_stages = glmsg.add_args();
+    arg_stages->set_isarray(false);
+    arg_stages->set_type(GLMessage::DataType::INT);
+    arg_stages->add_intvalue(stages);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glUseProgramStagesEXT(pipeline, stages, program);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glActiveShaderProgramEXT(GLuint pipeline, GLuint program) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glActiveShaderProgramEXT);
+
+    // copy argument pipeline
+    GLMessage_DataType *arg_pipeline = glmsg.add_args();
+    arg_pipeline->set_isarray(false);
+    arg_pipeline->set_type(GLMessage::DataType::INT);
+    arg_pipeline->add_intvalue(pipeline);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glActiveShaderProgramEXT(pipeline, program);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+GLuint GLTrace_glCreateShaderProgramvEXT(GLenum type, GLsizei count, const GLchar **strings) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glCreateShaderProgramvEXT);
+
+    // copy argument type
+    GLMessage_DataType *arg_type = glmsg.add_args();
+    arg_type->set_isarray(false);
+    arg_type->set_type(GLMessage::DataType::ENUM);
+    arg_type->add_intvalue((int)type);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument strings
+    GLMessage_DataType *arg_strings = glmsg.add_args();
+    arg_strings->set_isarray(false);
+    arg_strings->set_type(GLMessage::DataType::INT);
+    arg_strings->add_intvalue((int)strings);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    GLuint retValue = glContext->hooks->gl.glCreateShaderProgramvEXT(type, count, strings);
+    nsecs_t end_time = systemTime();
+
+    // set return value
+    GLMessage_DataType *rt = glmsg.mutable_returnvalue();
+    rt->set_isarray(false);
+    rt->set_type(GLMessage::DataType::INT);
+    rt->add_intvalue(retValue);
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+
+    return retValue;
+}
+
+void GLTrace_glBindProgramPipelineEXT(GLuint pipeline) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glBindProgramPipelineEXT);
+
+    // copy argument pipeline
+    GLMessage_DataType *arg_pipeline = glmsg.add_args();
+    arg_pipeline->set_isarray(false);
+    arg_pipeline->set_type(GLMessage::DataType::INT);
+    arg_pipeline->add_intvalue(pipeline);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glBindProgramPipelineEXT(pipeline);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glDeleteProgramPipelinesEXT(GLsizei n, const GLuint *pipelines) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glDeleteProgramPipelinesEXT);
+
+    // copy argument n
+    GLMessage_DataType *arg_n = glmsg.add_args();
+    arg_n->set_isarray(false);
+    arg_n->set_type(GLMessage::DataType::INT);
+    arg_n->add_intvalue(n);
+
+    // copy argument pipelines
+    GLMessage_DataType *arg_pipelines = glmsg.add_args();
+    arg_pipelines->set_isarray(false);
+    arg_pipelines->set_type(GLMessage::DataType::INT);
+    arg_pipelines->add_intvalue((int)pipelines);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glDeleteProgramPipelinesEXT(n, pipelines);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGenProgramPipelinesEXT(GLsizei n, GLuint *pipelines) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGenProgramPipelinesEXT);
+
+    // copy argument n
+    GLMessage_DataType *arg_n = glmsg.add_args();
+    arg_n->set_isarray(false);
+    arg_n->set_type(GLMessage::DataType::INT);
+    arg_n->add_intvalue(n);
+
+    // copy argument pipelines
+    GLMessage_DataType *arg_pipelines = glmsg.add_args();
+    arg_pipelines->set_isarray(false);
+    arg_pipelines->set_type(GLMessage::DataType::INT);
+    arg_pipelines->add_intvalue((int)pipelines);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glGenProgramPipelinesEXT(n, pipelines);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+GLboolean GLTrace_glIsProgramPipelineEXT(GLuint pipeline) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glIsProgramPipelineEXT);
+
+    // copy argument pipeline
+    GLMessage_DataType *arg_pipeline = glmsg.add_args();
+    arg_pipeline->set_isarray(false);
+    arg_pipeline->set_type(GLMessage::DataType::INT);
+    arg_pipeline->add_intvalue(pipeline);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    GLboolean retValue = glContext->hooks->gl.glIsProgramPipelineEXT(pipeline);
+    nsecs_t end_time = systemTime();
+
+    // set return value
+    GLMessage_DataType *rt = glmsg.mutable_returnvalue();
+    rt->set_isarray(false);
+    rt->set_type(GLMessage::DataType::BOOL);
+    rt->add_boolvalue(retValue);
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+
+    return retValue;
+}
+
+void GLTrace_glProgramParameteriEXT(GLuint program, GLenum pname, GLint value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramParameteriEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument pname
+    GLMessage_DataType *arg_pname = glmsg.add_args();
+    arg_pname->set_isarray(false);
+    arg_pname->set_type(GLMessage::DataType::ENUM);
+    arg_pname->add_intvalue((int)pname);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue(value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramParameteriEXT(program, pname, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetProgramPipelineivEXT(GLuint pipeline, GLenum pname, GLint *params) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGetProgramPipelineivEXT);
+
+    // copy argument pipeline
+    GLMessage_DataType *arg_pipeline = glmsg.add_args();
+    arg_pipeline->set_isarray(false);
+    arg_pipeline->set_type(GLMessage::DataType::INT);
+    arg_pipeline->add_intvalue(pipeline);
+
+    // copy argument pname
+    GLMessage_DataType *arg_pname = glmsg.add_args();
+    arg_pname->set_isarray(false);
+    arg_pname->set_type(GLMessage::DataType::ENUM);
+    arg_pname->add_intvalue((int)pname);
+
+    // copy argument params
+    GLMessage_DataType *arg_params = glmsg.add_args();
+    arg_params->set_isarray(false);
+    arg_params->set_type(GLMessage::DataType::INT);
+    arg_params->add_intvalue((int)params);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glGetProgramPipelineivEXT(pipeline, pname, params);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform1iEXT(GLuint program, GLint location, GLint x) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform1iEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument x
+    GLMessage_DataType *arg_x = glmsg.add_args();
+    arg_x->set_isarray(false);
+    arg_x->set_type(GLMessage::DataType::INT);
+    arg_x->add_intvalue(x);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform1iEXT(program, location, x);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform2iEXT(GLuint program, GLint location, GLint x, GLint y) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform2iEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument x
+    GLMessage_DataType *arg_x = glmsg.add_args();
+    arg_x->set_isarray(false);
+    arg_x->set_type(GLMessage::DataType::INT);
+    arg_x->add_intvalue(x);
+
+    // copy argument y
+    GLMessage_DataType *arg_y = glmsg.add_args();
+    arg_y->set_isarray(false);
+    arg_y->set_type(GLMessage::DataType::INT);
+    arg_y->add_intvalue(y);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform2iEXT(program, location, x, y);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform3iEXT(GLuint program, GLint location, GLint x, GLint y, GLint z) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform3iEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument x
+    GLMessage_DataType *arg_x = glmsg.add_args();
+    arg_x->set_isarray(false);
+    arg_x->set_type(GLMessage::DataType::INT);
+    arg_x->add_intvalue(x);
+
+    // copy argument y
+    GLMessage_DataType *arg_y = glmsg.add_args();
+    arg_y->set_isarray(false);
+    arg_y->set_type(GLMessage::DataType::INT);
+    arg_y->add_intvalue(y);
+
+    // copy argument z
+    GLMessage_DataType *arg_z = glmsg.add_args();
+    arg_z->set_isarray(false);
+    arg_z->set_type(GLMessage::DataType::INT);
+    arg_z->add_intvalue(z);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform3iEXT(program, location, x, y, z);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform4iEXT(GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform4iEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument x
+    GLMessage_DataType *arg_x = glmsg.add_args();
+    arg_x->set_isarray(false);
+    arg_x->set_type(GLMessage::DataType::INT);
+    arg_x->add_intvalue(x);
+
+    // copy argument y
+    GLMessage_DataType *arg_y = glmsg.add_args();
+    arg_y->set_isarray(false);
+    arg_y->set_type(GLMessage::DataType::INT);
+    arg_y->add_intvalue(y);
+
+    // copy argument z
+    GLMessage_DataType *arg_z = glmsg.add_args();
+    arg_z->set_isarray(false);
+    arg_z->set_type(GLMessage::DataType::INT);
+    arg_z->add_intvalue(z);
+
+    // copy argument w
+    GLMessage_DataType *arg_w = glmsg.add_args();
+    arg_w->set_isarray(false);
+    arg_w->set_type(GLMessage::DataType::INT);
+    arg_w->add_intvalue(w);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform4iEXT(program, location, x, y, z, w);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform1fEXT(GLuint program, GLint location, GLfloat x) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform1fEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument x
+    GLMessage_DataType *arg_x = glmsg.add_args();
+    arg_x->set_isarray(false);
+    arg_x->set_type(GLMessage::DataType::FLOAT);
+    arg_x->add_floatvalue(x);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform1fEXT(program, location, x);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform2fEXT(GLuint program, GLint location, GLfloat x, GLfloat y) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform2fEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument x
+    GLMessage_DataType *arg_x = glmsg.add_args();
+    arg_x->set_isarray(false);
+    arg_x->set_type(GLMessage::DataType::FLOAT);
+    arg_x->add_floatvalue(x);
+
+    // copy argument y
+    GLMessage_DataType *arg_y = glmsg.add_args();
+    arg_y->set_isarray(false);
+    arg_y->set_type(GLMessage::DataType::FLOAT);
+    arg_y->add_floatvalue(y);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform2fEXT(program, location, x, y);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform3fEXT(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform3fEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument x
+    GLMessage_DataType *arg_x = glmsg.add_args();
+    arg_x->set_isarray(false);
+    arg_x->set_type(GLMessage::DataType::FLOAT);
+    arg_x->add_floatvalue(x);
+
+    // copy argument y
+    GLMessage_DataType *arg_y = glmsg.add_args();
+    arg_y->set_isarray(false);
+    arg_y->set_type(GLMessage::DataType::FLOAT);
+    arg_y->add_floatvalue(y);
+
+    // copy argument z
+    GLMessage_DataType *arg_z = glmsg.add_args();
+    arg_z->set_isarray(false);
+    arg_z->set_type(GLMessage::DataType::FLOAT);
+    arg_z->add_floatvalue(z);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform3fEXT(program, location, x, y, z);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform4fEXT(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform4fEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument x
+    GLMessage_DataType *arg_x = glmsg.add_args();
+    arg_x->set_isarray(false);
+    arg_x->set_type(GLMessage::DataType::FLOAT);
+    arg_x->add_floatvalue(x);
+
+    // copy argument y
+    GLMessage_DataType *arg_y = glmsg.add_args();
+    arg_y->set_isarray(false);
+    arg_y->set_type(GLMessage::DataType::FLOAT);
+    arg_y->add_floatvalue(y);
+
+    // copy argument z
+    GLMessage_DataType *arg_z = glmsg.add_args();
+    arg_z->set_isarray(false);
+    arg_z->set_type(GLMessage::DataType::FLOAT);
+    arg_z->add_floatvalue(z);
+
+    // copy argument w
+    GLMessage_DataType *arg_w = glmsg.add_args();
+    arg_w->set_isarray(false);
+    arg_w->set_type(GLMessage::DataType::FLOAT);
+    arg_w->add_floatvalue(w);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform4fEXT(program, location, x, y, z, w);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform1ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform1ivEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform1ivEXT(program, location, count, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform2ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform2ivEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform2ivEXT(program, location, count, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform3ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform3ivEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform3ivEXT(program, location, count, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform4ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform4ivEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform4ivEXT(program, location, count, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform1fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform1fvEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform1fvEXT(program, location, count, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform2fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform2fvEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform2fvEXT(program, location, count, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform3fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform3fvEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform3fvEXT(program, location, count, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform4fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniform4fvEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniform4fvEXT(program, location, count, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniformMatrix2fvEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument transpose
+    GLMessage_DataType *arg_transpose = glmsg.add_args();
+    arg_transpose->set_isarray(false);
+    arg_transpose->set_type(GLMessage::DataType::BOOL);
+    arg_transpose->add_boolvalue(transpose);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniformMatrix2fvEXT(program, location, count, transpose, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniformMatrix3fvEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument transpose
+    GLMessage_DataType *arg_transpose = glmsg.add_args();
+    arg_transpose->set_isarray(false);
+    arg_transpose->set_type(GLMessage::DataType::BOOL);
+    arg_transpose->add_boolvalue(transpose);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniformMatrix3fvEXT(program, location, count, transpose, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glProgramUniformMatrix4fvEXT);
+
+    // copy argument program
+    GLMessage_DataType *arg_program = glmsg.add_args();
+    arg_program->set_isarray(false);
+    arg_program->set_type(GLMessage::DataType::INT);
+    arg_program->add_intvalue(program);
+
+    // copy argument location
+    GLMessage_DataType *arg_location = glmsg.add_args();
+    arg_location->set_isarray(false);
+    arg_location->set_type(GLMessage::DataType::INT);
+    arg_location->add_intvalue(location);
+
+    // copy argument count
+    GLMessage_DataType *arg_count = glmsg.add_args();
+    arg_count->set_isarray(false);
+    arg_count->set_type(GLMessage::DataType::INT);
+    arg_count->add_intvalue(count);
+
+    // copy argument transpose
+    GLMessage_DataType *arg_transpose = glmsg.add_args();
+    arg_transpose->set_isarray(false);
+    arg_transpose->set_type(GLMessage::DataType::BOOL);
+    arg_transpose->add_boolvalue(transpose);
+
+    // copy argument value
+    GLMessage_DataType *arg_value = glmsg.add_args();
+    arg_value->set_isarray(false);
+    arg_value->set_type(GLMessage::DataType::INT);
+    arg_value->add_intvalue((int)value);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glProgramUniformMatrix4fvEXT(program, location, count, transpose, value);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glValidateProgramPipelineEXT(GLuint pipeline) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glValidateProgramPipelineEXT);
+
+    // copy argument pipeline
+    GLMessage_DataType *arg_pipeline = glmsg.add_args();
+    arg_pipeline->set_isarray(false);
+    arg_pipeline->set_type(GLMessage::DataType::INT);
+    arg_pipeline->add_intvalue(pipeline);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glValidateProgramPipelineEXT(pipeline);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetProgramPipelineInfoLogEXT(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glGetProgramPipelineInfoLogEXT);
+
+    // copy argument pipeline
+    GLMessage_DataType *arg_pipeline = glmsg.add_args();
+    arg_pipeline->set_isarray(false);
+    arg_pipeline->set_type(GLMessage::DataType::INT);
+    arg_pipeline->add_intvalue(pipeline);
+
+    // copy argument bufSize
+    GLMessage_DataType *arg_bufSize = glmsg.add_args();
+    arg_bufSize->set_isarray(false);
+    arg_bufSize->set_type(GLMessage::DataType::INT);
+    arg_bufSize->add_intvalue(bufSize);
+
+    // copy argument length
+    GLMessage_DataType *arg_length = glmsg.add_args();
+    arg_length->set_isarray(false);
+    arg_length->set_type(GLMessage::DataType::INT);
+    arg_length->add_intvalue((int)length);
+
+    // copy argument infoLog
+    GLMessage_DataType *arg_infoLog = glmsg.add_args();
+    arg_infoLog->set_isarray(false);
+    arg_infoLog->set_type(GLMessage::DataType::INT);
+    arg_infoLog->add_intvalue((int)infoLog);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glGetProgramPipelineInfoLogEXT(pipeline, bufSize, length, infoLog);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTexStorage1DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glTexStorage1DEXT);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument levels
+    GLMessage_DataType *arg_levels = glmsg.add_args();
+    arg_levels->set_isarray(false);
+    arg_levels->set_type(GLMessage::DataType::INT);
+    arg_levels->add_intvalue(levels);
+
+    // copy argument internalformat
+    GLMessage_DataType *arg_internalformat = glmsg.add_args();
+    arg_internalformat->set_isarray(false);
+    arg_internalformat->set_type(GLMessage::DataType::ENUM);
+    arg_internalformat->add_intvalue((int)internalformat);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glTexStorage1DEXT(target, levels, internalformat, width);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glTexStorage2DEXT);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument levels
+    GLMessage_DataType *arg_levels = glmsg.add_args();
+    arg_levels->set_isarray(false);
+    arg_levels->set_type(GLMessage::DataType::INT);
+    arg_levels->add_intvalue(levels);
+
+    // copy argument internalformat
+    GLMessage_DataType *arg_internalformat = glmsg.add_args();
+    arg_internalformat->set_isarray(false);
+    arg_internalformat->set_type(GLMessage::DataType::ENUM);
+    arg_internalformat->add_intvalue((int)internalformat);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // copy argument height
+    GLMessage_DataType *arg_height = glmsg.add_args();
+    arg_height->set_isarray(false);
+    arg_height->set_type(GLMessage::DataType::INT);
+    arg_height->add_intvalue(height);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glTexStorage2DEXT(target, levels, internalformat, width, height);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTexStorage3DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glTexStorage3DEXT);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument levels
+    GLMessage_DataType *arg_levels = glmsg.add_args();
+    arg_levels->set_isarray(false);
+    arg_levels->set_type(GLMessage::DataType::INT);
+    arg_levels->add_intvalue(levels);
+
+    // copy argument internalformat
+    GLMessage_DataType *arg_internalformat = glmsg.add_args();
+    arg_internalformat->set_isarray(false);
+    arg_internalformat->set_type(GLMessage::DataType::ENUM);
+    arg_internalformat->add_intvalue((int)internalformat);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // copy argument height
+    GLMessage_DataType *arg_height = glmsg.add_args();
+    arg_height->set_isarray(false);
+    arg_height->set_type(GLMessage::DataType::INT);
+    arg_height->add_intvalue(height);
+
+    // copy argument depth
+    GLMessage_DataType *arg_depth = glmsg.add_args();
+    arg_depth->set_isarray(false);
+    arg_depth->set_type(GLMessage::DataType::INT);
+    arg_depth->add_intvalue(depth);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glTexStorage3DEXT(target, levels, internalformat, width, height, depth);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glTextureStorage1DEXT);
+
+    // copy argument texture
+    GLMessage_DataType *arg_texture = glmsg.add_args();
+    arg_texture->set_isarray(false);
+    arg_texture->set_type(GLMessage::DataType::INT);
+    arg_texture->add_intvalue(texture);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument levels
+    GLMessage_DataType *arg_levels = glmsg.add_args();
+    arg_levels->set_isarray(false);
+    arg_levels->set_type(GLMessage::DataType::INT);
+    arg_levels->add_intvalue(levels);
+
+    // copy argument internalformat
+    GLMessage_DataType *arg_internalformat = glmsg.add_args();
+    arg_internalformat->set_isarray(false);
+    arg_internalformat->set_type(GLMessage::DataType::ENUM);
+    arg_internalformat->add_intvalue((int)internalformat);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glTextureStorage1DEXT(texture, target, levels, internalformat, width);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glTextureStorage2DEXT);
+
+    // copy argument texture
+    GLMessage_DataType *arg_texture = glmsg.add_args();
+    arg_texture->set_isarray(false);
+    arg_texture->set_type(GLMessage::DataType::INT);
+    arg_texture->add_intvalue(texture);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument levels
+    GLMessage_DataType *arg_levels = glmsg.add_args();
+    arg_levels->set_isarray(false);
+    arg_levels->set_type(GLMessage::DataType::INT);
+    arg_levels->add_intvalue(levels);
+
+    // copy argument internalformat
+    GLMessage_DataType *arg_internalformat = glmsg.add_args();
+    arg_internalformat->set_isarray(false);
+    arg_internalformat->set_type(GLMessage::DataType::ENUM);
+    arg_internalformat->add_intvalue((int)internalformat);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // copy argument height
+    GLMessage_DataType *arg_height = glmsg.add_args();
+    arg_height->set_isarray(false);
+    arg_height->set_type(GLMessage::DataType::INT);
+    arg_height->add_intvalue(height);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glTextureStorage2DEXT(texture, target, levels, internalformat, width, height);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glTextureStorage3DEXT);
+
+    // copy argument texture
+    GLMessage_DataType *arg_texture = glmsg.add_args();
+    arg_texture->set_isarray(false);
+    arg_texture->set_type(GLMessage::DataType::INT);
+    arg_texture->add_intvalue(texture);
+
+    // copy argument target
+    GLMessage_DataType *arg_target = glmsg.add_args();
+    arg_target->set_isarray(false);
+    arg_target->set_type(GLMessage::DataType::ENUM);
+    arg_target->add_intvalue((int)target);
+
+    // copy argument levels
+    GLMessage_DataType *arg_levels = glmsg.add_args();
+    arg_levels->set_isarray(false);
+    arg_levels->set_type(GLMessage::DataType::INT);
+    arg_levels->add_intvalue(levels);
+
+    // copy argument internalformat
+    GLMessage_DataType *arg_internalformat = glmsg.add_args();
+    arg_internalformat->set_isarray(false);
+    arg_internalformat->set_type(GLMessage::DataType::ENUM);
+    arg_internalformat->add_intvalue((int)internalformat);
+
+    // copy argument width
+    GLMessage_DataType *arg_width = glmsg.add_args();
+    arg_width->set_isarray(false);
+    arg_width->set_type(GLMessage::DataType::INT);
+    arg_width->add_intvalue(width);
+
+    // copy argument height
+    GLMessage_DataType *arg_height = glmsg.add_args();
+    arg_height->set_isarray(false);
+    arg_height->set_type(GLMessage::DataType::INT);
+    arg_height->add_intvalue(height);
+
+    // copy argument depth
+    GLMessage_DataType *arg_depth = glmsg.add_args();
+    arg_depth->set_isarray(false);
+    arg_depth->set_type(GLMessage::DataType::INT);
+    arg_depth->add_intvalue(depth);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glTextureStorage3DEXT(texture, target, levels, internalformat, width, height, depth);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
 void GLTrace_glRenderbufferStorageMultisampleIMG(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
     GLMessage glmsg;
     GLTraceContext *glContext = getGLTraceContext();
@@ -6022,6 +8214,75 @@
     glContext->traceGLMessage(&glmsg);
 }
 
+void GLTrace_glCoverageMaskNV(GLboolean mask) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glCoverageMaskNV);
+
+    // copy argument mask
+    GLMessage_DataType *arg_mask = glmsg.add_args();
+    arg_mask->set_isarray(false);
+    arg_mask->set_type(GLMessage::DataType::BOOL);
+    arg_mask->add_boolvalue(mask);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glCoverageMaskNV(mask);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glCoverageOperationNV(GLenum operation) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glCoverageOperationNV);
+
+    // copy argument operation
+    GLMessage_DataType *arg_operation = glmsg.add_args();
+    arg_operation->set_isarray(false);
+    arg_operation->set_type(GLMessage::DataType::ENUM);
+    arg_operation->add_intvalue((int)operation);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glCoverageOperationNV(operation);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glDrawBuffersNV(GLsizei n, const GLenum *bufs) {
+    GLMessage glmsg;
+    GLTraceContext *glContext = getGLTraceContext();
+
+    glmsg.set_function(GLMessage::glDrawBuffersNV);
+
+    // copy argument n
+    GLMessage_DataType *arg_n = glmsg.add_args();
+    arg_n->set_isarray(false);
+    arg_n->set_type(GLMessage::DataType::INT);
+    arg_n->add_intvalue(n);
+
+    // copy argument bufs
+    GLMessage_DataType *arg_bufs = glmsg.add_args();
+    arg_bufs->set_isarray(false);
+    arg_bufs->set_type(GLMessage::DataType::INT);
+    arg_bufs->add_intvalue((int)bufs);
+
+    // call function
+    nsecs_t start_time = systemTime();
+    glContext->hooks->gl.glDrawBuffersNV(n, bufs);
+    nsecs_t end_time = systemTime();
+
+    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    glContext->traceGLMessage(&glmsg);
+}
+
 void GLTrace_glDeleteFencesNV(GLsizei n, const GLuint *fences) {
     GLMessage glmsg;
     GLTraceContext *glContext = getGLTraceContext();
@@ -6215,42 +8476,48 @@
     glContext->traceGLMessage(&glmsg);
 }
 
-void GLTrace_glCoverageMaskNV(GLboolean mask) {
+void GLTrace_glReadBufferNV(GLenum mode) {
     GLMessage glmsg;
     GLTraceContext *glContext = getGLTraceContext();
 
-    glmsg.set_function(GLMessage::glCoverageMaskNV);
+    glmsg.set_function(GLMessage::glReadBufferNV);
 
-    // copy argument mask
-    GLMessage_DataType *arg_mask = glmsg.add_args();
-    arg_mask->set_isarray(false);
-    arg_mask->set_type(GLMessage::DataType::BOOL);
-    arg_mask->add_boolvalue(mask);
+    // copy argument mode
+    GLMessage_DataType *arg_mode = glmsg.add_args();
+    arg_mode->set_isarray(false);
+    arg_mode->set_type(GLMessage::DataType::ENUM);
+    arg_mode->add_intvalue((int)mode);
 
     // call function
     nsecs_t start_time = systemTime();
-    glContext->hooks->gl.glCoverageMaskNV(mask);
+    glContext->hooks->gl.glReadBufferNV(mode);
     nsecs_t end_time = systemTime();
 
     fixupGLMessage(glContext, start_time, end_time, &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
-void GLTrace_glCoverageOperationNV(GLenum operation) {
+void GLTrace_glAlphaFuncQCOM(GLenum func, GLclampf ref) {
     GLMessage glmsg;
     GLTraceContext *glContext = getGLTraceContext();
 
-    glmsg.set_function(GLMessage::glCoverageOperationNV);
+    glmsg.set_function(GLMessage::glAlphaFuncQCOM);
 
-    // copy argument operation
-    GLMessage_DataType *arg_operation = glmsg.add_args();
-    arg_operation->set_isarray(false);
-    arg_operation->set_type(GLMessage::DataType::ENUM);
-    arg_operation->add_intvalue((int)operation);
+    // copy argument func
+    GLMessage_DataType *arg_func = glmsg.add_args();
+    arg_func->set_isarray(false);
+    arg_func->set_type(GLMessage::DataType::ENUM);
+    arg_func->add_intvalue((int)func);
+
+    // copy argument ref
+    GLMessage_DataType *arg_ref = glmsg.add_args();
+    arg_ref->set_isarray(false);
+    arg_ref->set_type(GLMessage::DataType::FLOAT);
+    arg_ref->add_floatvalue(ref);
 
     // call function
     nsecs_t start_time = systemTime();
-    glContext->hooks->gl.glCoverageOperationNV(operation);
+    glContext->hooks->gl.glAlphaFuncQCOM(func, ref);
     nsecs_t end_time = systemTime();
 
     fixupGLMessage(glContext, start_time, end_time, &glmsg);
diff --git a/opengl/libs/GLES_trace/src/gltrace_api.h b/opengl/libs/GLES_trace/src/gltrace_api.h
index 71b5a584..debcac0 100644
--- a/opengl/libs/GLES_trace/src/gltrace_api.h
+++ b/opengl/libs/GLES_trace/src/gltrace_api.h
@@ -194,11 +194,72 @@
 void GLTrace_glBeginPerfMonitorAMD(GLuint monitor);
 void GLTrace_glEndPerfMonitorAMD(GLuint monitor);
 void GLTrace_glGetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+void GLTrace_glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+void GLTrace_glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glRenderbufferStorageMultisampleAPPLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glResolveMultisampleFramebufferAPPLE(void);
+void GLTrace_glLabelObjectEXT(GLenum type, GLuint object, GLsizei length, const GLchar *label);
+void GLTrace_glGetObjectLabelEXT(GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+void GLTrace_glInsertEventMarkerEXT(GLsizei length, const GLchar *marker);
+void GLTrace_glPushGroupMarkerEXT(GLsizei length, const GLchar *marker);
+void GLTrace_glPopGroupMarkerEXT(void);
 void GLTrace_glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments);
+void GLTrace_glRenderbufferStorageMultisampleEXT(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glFramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
 void GLTrace_glMultiDrawArraysEXT(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
 void GLTrace_glMultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+void GLTrace_glGenQueriesEXT(GLsizei n, GLuint *ids);
+void GLTrace_glDeleteQueriesEXT(GLsizei n, const GLuint *ids);
+GLboolean GLTrace_glIsQueryEXT(GLuint id);
+void GLTrace_glBeginQueryEXT(GLenum target, GLuint id);
+void GLTrace_glEndQueryEXT(GLenum target);
+void GLTrace_glGetQueryivEXT(GLenum target, GLenum pname, GLint *params);
+void GLTrace_glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params);
+GLenum GLTrace_glGetGraphicsResetStatusEXT(void);
+void GLTrace_glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+void GLTrace_glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, float *params);
+void GLTrace_glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint *params);
+void GLTrace_glUseProgramStagesEXT(GLuint pipeline, GLbitfield stages, GLuint program);
+void GLTrace_glActiveShaderProgramEXT(GLuint pipeline, GLuint program);
+GLuint GLTrace_glCreateShaderProgramvEXT(GLenum type, GLsizei count, const GLchar **strings);
+void GLTrace_glBindProgramPipelineEXT(GLuint pipeline);
+void GLTrace_glDeleteProgramPipelinesEXT(GLsizei n, const GLuint *pipelines);
+void GLTrace_glGenProgramPipelinesEXT(GLsizei n, GLuint *pipelines);
+GLboolean GLTrace_glIsProgramPipelineEXT(GLuint pipeline);
+void GLTrace_glProgramParameteriEXT(GLuint program, GLenum pname, GLint value);
+void GLTrace_glGetProgramPipelineivEXT(GLuint pipeline, GLenum pname, GLint *params);
+void GLTrace_glProgramUniform1iEXT(GLuint program, GLint location, GLint x);
+void GLTrace_glProgramUniform2iEXT(GLuint program, GLint location, GLint x, GLint y);
+void GLTrace_glProgramUniform3iEXT(GLuint program, GLint location, GLint x, GLint y, GLint z);
+void GLTrace_glProgramUniform4iEXT(GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+void GLTrace_glProgramUniform1fEXT(GLuint program, GLint location, GLfloat x);
+void GLTrace_glProgramUniform2fEXT(GLuint program, GLint location, GLfloat x, GLfloat y);
+void GLTrace_glProgramUniform3fEXT(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+void GLTrace_glProgramUniform4fEXT(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void GLTrace_glProgramUniform1ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value);
+void GLTrace_glProgramUniform2ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value);
+void GLTrace_glProgramUniform3ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value);
+void GLTrace_glProgramUniform4ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value);
+void GLTrace_glProgramUniform1fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void GLTrace_glProgramUniform2fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void GLTrace_glProgramUniform3fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void GLTrace_glProgramUniform4fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void GLTrace_glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void GLTrace_glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void GLTrace_glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void GLTrace_glValidateProgramPipelineEXT(GLuint pipeline);
+void GLTrace_glGetProgramPipelineInfoLogEXT(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+void GLTrace_glTexStorage1DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+void GLTrace_glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glTexStorage3DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+void GLTrace_glTextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+void GLTrace_glTextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glTextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
 void GLTrace_glRenderbufferStorageMultisampleIMG(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
 void GLTrace_glFramebufferTexture2DMultisampleIMG(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+void GLTrace_glCoverageMaskNV(GLboolean mask);
+void GLTrace_glCoverageOperationNV(GLenum operation);
+void GLTrace_glDrawBuffersNV(GLsizei n, const GLenum *bufs);
 void GLTrace_glDeleteFencesNV(GLsizei n, const GLuint *fences);
 void GLTrace_glGenFencesNV(GLsizei n, GLuint *fences);
 GLboolean GLTrace_glIsFenceNV(GLuint fence);
@@ -206,8 +267,8 @@
 void GLTrace_glGetFenceivNV(GLuint fence, GLenum pname, GLint *params);
 void GLTrace_glFinishFenceNV(GLuint fence);
 void GLTrace_glSetFenceNV(GLuint fence, GLenum condition);
-void GLTrace_glCoverageMaskNV(GLboolean mask);
-void GLTrace_glCoverageOperationNV(GLenum operation);
+void GLTrace_glReadBufferNV(GLenum mode);
+void GLTrace_glAlphaFuncQCOM(GLenum func, GLclampf ref);
 void GLTrace_glGetDriverControlsQCOM(GLint *num, GLsizei size, GLuint *driverControls);
 void GLTrace_glGetDriverControlStringQCOM(GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
 void GLTrace_glEnableDriverControlQCOM(GLuint driverControl);
diff --git a/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp b/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
index c237d75..c442153 100644
--- a/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
@@ -77,12 +77,10 @@
 }
 
 void GLTrace_start() {
-    char value[PROPERTY_VALUE_MAX];
+    char udsName[PROPERTY_VALUE_MAX];
 
-    property_get("debug.egl.debug_port", value, "5039");
-    const unsigned short port = (unsigned short)atoi(value);
-
-    int clientSocket = gltrace::acceptClientConnection(port);
+    property_get("debug.egl.debug_portname", udsName, "gltrace");
+    int clientSocket = gltrace::acceptClientConnection(udsName);
     if (clientSocket < 0) {
         ALOGE("Error creating GLTrace server socket. Quitting application.");
         exit(-1);
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index daba3ff..871b5dc 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -358,6 +358,14 @@
             fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
         }
         break;
+    case GLMessage::glPushGroupMarkerEXT:
+        /* void PushGroupMarkerEXT(sizei length, const char *marker); */
+        fixup_CStringPtr(1, glmsg);
+        break;
+    case GLMessage::glInsertEventMarkerEXT:
+        /* void InsertEventMarkerEXT(sizei length, const char *marker); */
+        fixup_CStringPtr(1, glmsg);
+        break;
     default:
         break;
     }
diff --git a/opengl/libs/GLES_trace/src/gltrace_transport.cpp b/opengl/libs/GLES_trace/src/gltrace_transport.cpp
index ce3fae5..5251b12 100644
--- a/opengl/libs/GLES_trace/src/gltrace_transport.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_transport.cpp
@@ -17,9 +17,10 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <unistd.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <netinet/in.h>
-#include <arpa/inet.h>
 
 #include <cutils/log.h>
 
@@ -28,22 +29,24 @@
 namespace android {
 namespace gltrace {
 
-int acceptClientConnection(int serverPort) {
-    int serverSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+int acceptClientConnection(char *sockname) {
+    int serverSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
     if (serverSocket < 0) {
         ALOGE("Error (%d) while creating socket. Check if app has network permissions.",
                                                                             serverSocket);
         return -1;
     }
 
-    struct sockaddr_in server, client;
+    struct sockaddr_un server, client;
 
-    server.sin_family = AF_INET;
-    server.sin_addr.s_addr = htonl(INADDR_ANY);
-    server.sin_port = htons(serverPort);
+    memset(&server, 0, sizeof server);
+    server.sun_family = AF_UNIX;
+    // the first byte of sun_path should be '\0' for abstract namespace
+    strcpy(server.sun_path + 1, sockname);
 
-    socklen_t sockaddr_len = sizeof(sockaddr_in);
-    if (bind(serverSocket, (struct sockaddr *) &server, sizeof(server)) < 0) {
+    // note that sockaddr_len should be set to the exact size of the buffer that is used.
+    socklen_t sockaddr_len = sizeof(server.sun_family) + strlen(sockname) + 1;
+    if (bind(serverSocket, (struct sockaddr *) &server, sockaddr_len) < 0) {
         close(serverSocket);
         ALOGE("Failed to bind the server socket");
         return -1;
@@ -55,7 +58,7 @@
         return -1;
     }
 
-    ALOGD("gltrace::waitForClientConnection: server listening @ port %d", serverPort);
+    ALOGD("gltrace::waitForClientConnection: server listening @ path %s", sockname);
 
     int clientSocket = accept(serverSocket, (struct sockaddr *)&client, &sockaddr_len);
     if (clientSocket < 0) {
@@ -64,7 +67,7 @@
         return -1;
     }
 
-    ALOGD("gltrace::waitForClientConnection: client connected: %s", inet_ntoa(client.sin_addr));
+    ALOGD("gltrace::waitForClientConnection: client connected.");
 
     // do not accept any more incoming connections
     close(serverSocket);
diff --git a/opengl/libs/GLES_trace/src/gltrace_transport.h b/opengl/libs/GLES_trace/src/gltrace_transport.h
index d31df7b..3665035 100644
--- a/opengl/libs/GLES_trace/src/gltrace_transport.h
+++ b/opengl/libs/GLES_trace/src/gltrace_transport.h
@@ -76,10 +76,11 @@
 };
 
 /**
- * Utility method: start a server at @serverPort, and wait for a client
- * connection. Returns the connected client socket on success, or -1 on failure.
+ * Utility method: start a server listening at @sockName (unix domain socket,
+ * abstract namespace path), and wait for a client connection.
+ * Returns the connected client socket on success, or -1 on failure.
  */
-int acceptClientConnection(int serverPort);
+int acceptClientConnection(char *sockName);
 
 };
 };
diff --git a/opengl/libs/GLES_trace/tools/genapi.py b/opengl/libs/GLES_trace/tools/genapi.py
index 9b7a1cf..557e407 100755
--- a/opengl/libs/GLES_trace/tools/genapi.py
+++ b/opengl/libs/GLES_trace/tools/genapi.py
@@ -26,11 +26,11 @@
 #   module. The only reason to use pyratemp is that it is extremly
 #   simple to install:
 #   $ wget http://www.simple-is-better.org/template/pyratemp-current/pyratemp.py
-#   Put the file in the GLES2_trace/tools folder, or update PYTHONPATH
+#   Put the file in the GLES_trace/tools folder, or update PYTHONPATH
 #   to point to wherever it was downloaded.
 #
 # USAGE
-#   $ cd GLES2_trace      - run the program from GLES2_trace folder
+#   $ cd GLES_trace       - run the program from GLES2_trace folder
 #   $ ./tools/genapi.py   - generates a .cpp and .h file
 #   $ mv *.cpp *.h src/   - move the generated files into the src folder
 
diff --git a/opengl/libs/GLES_trace/tools/testgenapi.py b/opengl/libs/GLES_trace/tools/testgenapi.py
index 58a12a8..fe14954 100644
--- a/opengl/libs/GLES_trace/tools/testgenapi.py
+++ b/opengl/libs/GLES_trace/tools/testgenapi.py
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 # USAGE
-#   $ cd GLES2_trace/tools
+#   $ cd GLES_trace/tools
 #   $ python testgenapi.py
 
 import unittest
@@ -45,9 +45,9 @@
         glext_apis = getApis('../../GLES_CM/glext_api.in', 'GL1Ext')
 
         self.assertEqual(len(gl2_apis), 142)
-        self.assertEqual(len(gl2ext_apis), 60)
+        self.assertEqual(len(gl2ext_apis), 121)
         self.assertEqual(len(gl_apis), 145)
-        self.assertEqual(len(glext_apis), 126)
+        self.assertEqual(len(glext_apis), 140)
 
     def test_parseArgs(self):
         args = parseArgs("void")
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index a809316..8ff51ec 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -29,6 +29,7 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name);
 EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/entries.in b/opengl/libs/entries.in
index 61acb5f..6316d78 100644
--- a/opengl/libs/entries.in
+++ b/opengl/libs/entries.in
@@ -1,13 +1,17 @@
+GL_ENTRY(void, glActiveShaderProgramEXT, GLuint pipeline, GLuint program)
 GL_ENTRY(void, glActiveTexture, GLenum texture)
 GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
+GL_ENTRY(void, glAlphaFuncQCOM, GLenum func, GLclampf ref)
 GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
 GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref)
 GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader)
 GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glBeginQueryEXT, GLenum target, GLuint id)
 GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const GLchar* name)
 GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
 GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer)
 GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindProgramPipelineEXT, GLuint pipeline)
 GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer)
 GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)
 GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
@@ -20,6 +24,7 @@
 GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
 GL_ENTRY(void, glBlendFuncSeparate, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
 GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBlitFramebufferANGLE, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
 GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
 GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
 GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target)
@@ -58,6 +63,7 @@
 GL_ENTRY(void, glCoverageOperationNV, GLenum operation)
 GL_ENTRY(GLuint, glCreateProgram, void)
 GL_ENTRY(GLuint, glCreateShader, GLenum type)
+GL_ENTRY(GLuint, glCreateShaderProgramvEXT, GLenum type, GLsizei count, const GLchar **strings)
 GL_ENTRY(void, glCullFace, GLenum mode)
 GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex)
 GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers)
@@ -66,6 +72,8 @@
 GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers)
 GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors)
 GL_ENTRY(void, glDeleteProgram, GLuint program)
+GL_ENTRY(void, glDeleteProgramPipelinesEXT, GLsizei n, const GLuint *pipelines)
+GL_ENTRY(void, glDeleteQueriesEXT, GLsizei n, const GLuint *ids)
 GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers)
 GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers)
 GL_ENTRY(void, glDeleteShader, GLuint shader)
@@ -84,6 +92,7 @@
 GL_ENTRY(void, glDisableVertexAttribArray, GLuint index)
 GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments)
 GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawBuffersNV, GLsizei n, const GLenum *bufs)
 GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
 GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
 GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords)
@@ -100,6 +109,7 @@
 GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
 GL_ENTRY(void, glEnableVertexAttribArray, GLuint index)
 GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glEndQueryEXT, GLenum target)
 GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask)
 GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, GLvoid **params)
 GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers)
@@ -125,6 +135,7 @@
 GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
 GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
 GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFramebufferTexture2DMultisampleEXT, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
 GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
 GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
 GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
@@ -138,6 +149,8 @@
 GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint* framebuffers)
 GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers)
 GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glGenProgramPipelinesEXT, GLsizei n, GLuint *pipelines)
+GL_ENTRY(void, glGenQueriesEXT, GLsizei n, GLuint *ids)
 GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers)
 GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers)
 GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
@@ -164,6 +177,7 @@
 GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params)
 GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params)
 GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(GLenum, glGetGraphicsResetStatusEXT, void)
 GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params)
 GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params)
 GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params)
@@ -171,6 +185,7 @@
 GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
 GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
 GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetObjectLabelEXT, GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label)
 GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten)
 GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, GLvoid *data)
 GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString)
@@ -180,7 +195,11 @@
 GL_ENTRY(void, glGetPointerv, GLenum pname, GLvoid **params)
 GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary)
 GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+GL_ENTRY(void, glGetProgramPipelineInfoLogEXT, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
+GL_ENTRY(void, glGetProgramPipelineivEXT, GLuint pipeline, GLenum pname, GLint *params)
 GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetQueryObjectuivEXT, GLuint id, GLenum pname, GLuint *params)
+GL_ENTRY(void, glGetQueryivEXT, GLenum target, GLenum pname, GLint *params)
 GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params)
 GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params)
 GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
@@ -205,18 +224,24 @@
 GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, GLvoid** pointer)
 GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params)
 GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetnUniformfvEXT, GLuint program, GLint location, GLsizei bufSize, float *params)
+GL_ENTRY(void, glGetnUniformivEXT, GLuint program, GLint location, GLsizei bufSize, GLint *params)
 GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(void, glInsertEventMarkerEXT, GLsizei length, const GLchar *marker)
 GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
 GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
 GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
 GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer)
 GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
 GL_ENTRY(GLboolean, glIsProgram, GLuint program)
+GL_ENTRY(GLboolean, glIsProgramPipelineEXT, GLuint pipeline)
+GL_ENTRY(GLboolean, glIsQueryEXT, GLuint id)
 GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer)
 GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
 GL_ENTRY(GLboolean, glIsShader, GLuint shader)
 GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
 GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array)
+GL_ENTRY(void, glLabelObjectEXT, GLenum type, GLuint object, GLsizei length, const GLchar *label)
 GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)
 GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)
 GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param)
@@ -278,15 +303,43 @@
 GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
 GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
 GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPopGroupMarkerEXT, void)
 GL_ENTRY(void, glPopMatrix, void)
 GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length)
+GL_ENTRY(void, glProgramParameteriEXT, GLuint program, GLenum pname, GLint value)
+GL_ENTRY(void, glProgramUniform1fEXT, GLuint program, GLint location, GLfloat x)
+GL_ENTRY(void, glProgramUniform1fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform1iEXT, GLuint program, GLint location, GLint x)
+GL_ENTRY(void, glProgramUniform1ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform2fEXT, GLuint program, GLint location, GLfloat x, GLfloat y)
+GL_ENTRY(void, glProgramUniform2fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform2iEXT, GLuint program, GLint location, GLint x, GLint y)
+GL_ENTRY(void, glProgramUniform2ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform3fEXT, GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glProgramUniform3fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform3iEXT, GLuint program, GLint location, GLint x, GLint y, GLint z)
+GL_ENTRY(void, glProgramUniform3ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform4fEXT, GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glProgramUniform4fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform4iEXT, GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w)
+GL_ENTRY(void, glProgramUniform4ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniformMatrix2fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix3fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glPushGroupMarkerEXT, GLsizei length, const GLchar *marker)
 GL_ENTRY(void, glPushMatrix, void)
 GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed mantissa[16], GLint exponent[16])
+GL_ENTRY(void, glReadBufferNV, GLenum mode)
 GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
+GL_ENTRY(void, glReadnPixelsEXT, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data)
 GL_ENTRY(void, glReleaseShaderCompiler, void)
 GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleANGLE, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleAPPLE, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleEXT, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
 GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
 GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glResolveMultisampleFramebufferAPPLE, void)
 GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
 GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
 GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
@@ -335,8 +388,14 @@
 GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)
 GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)
 GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexStorage1DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
+GL_ENTRY(void, glTexStorage2DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glTexStorage3DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
 GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
 GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glTextureStorage1DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
+GL_ENTRY(void, glTextureStorage2DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glTextureStorage3DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
 GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)
 GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)
 GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z)
@@ -361,7 +420,9 @@
 GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
 GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
 GL_ENTRY(void, glUseProgram, GLuint program)
+GL_ENTRY(void, glUseProgramStagesEXT, GLuint pipeline, GLbitfield stages, GLuint program)
 GL_ENTRY(void, glValidateProgram, GLuint program)
+GL_ENTRY(void, glValidateProgramPipelineEXT, GLuint pipeline)
 GL_ENTRY(void, glVertexAttrib1f, GLuint indx, GLfloat x)
 GL_ENTRY(void, glVertexAttrib1fv, GLuint indx, const GLfloat* values)
 GL_ENTRY(void, glVertexAttrib2f, GLuint indx, GLfloat x, GLfloat y)
diff --git a/opengl/libs/enums.in b/opengl/libs/enums.in
index f9752c2..bfbc866 100644
--- a/opengl/libs/enums.in
+++ b/opengl/libs/enums.in
@@ -1,4 +1,6 @@
 GL_ENUM(0x0000,GL_POINTS)
+GL_ENUM(0x00000001,GL_VERTEX_SHADER_BIT_EXT)
+GL_ENUM(0x00000002,GL_FRAGMENT_SHADER_BIT_EXT)
 GL_ENUM(0x0001,GL_LINES)
 GL_ENUM(0x0002,GL_LINE_LOOP)
 GL_ENUM(0x0003,GL_LINE_STRIP)
@@ -92,6 +94,7 @@
 GL_ENUM(0x0BE2,GL_BLEND)
 GL_ENUM(0x0BF0,GL_LOGIC_OP_MODE)
 GL_ENUM(0x0BF2,GL_COLOR_LOGIC_OP)
+GL_ENUM(0x0C02,GL_READ_BUFFER_NV)
 GL_ENUM(0x0C10,GL_SCISSOR_BOX)
 GL_ENUM(0x0C11,GL_SCISSOR_TEST)
 GL_ENUM(0x0C22,GL_COLOR_CLEAR_VALUE)
@@ -100,6 +103,9 @@
 GL_ENUM(0x0C51,GL_POINT_SMOOTH_HINT)
 GL_ENUM(0x0C52,GL_LINE_SMOOTH_HINT)
 GL_ENUM(0x0C54,GL_FOG_HINT)
+GL_ENUM(0x0CF2,GL_UNPACK_ROW_LENGTH)
+GL_ENUM(0x0CF3,GL_UNPACK_SKIP_ROWS)
+GL_ENUM(0x0CF4,GL_UNPACK_SKIP_PIXELS)
 GL_ENUM(0x0CF5,GL_UNPACK_ALIGNMENT)
 GL_ENUM(0x0D05,GL_PACK_ALIGNMENT)
 GL_ENUM(0x0D1C,GL_ALPHA_SCALE)
@@ -166,6 +172,7 @@
 GL_ENUM(0x1802,GL_STENCIL_EXT)
 GL_ENUM(0x1901,GL_STENCIL_INDEX)
 GL_ENUM(0x1902,GL_DEPTH_COMPONENT)
+GL_ENUM(0x1903,GL_RED_EXT)
 GL_ENUM(0x1906,GL_ALPHA)
 GL_ENUM(0x1907,GL_RGB)
 GL_ENUM(0x1908,GL_RGBA)
@@ -230,10 +237,15 @@
 GL_ENUM(0x8037,GL_POLYGON_OFFSET_FILL)
 GL_ENUM(0x8038,GL_POLYGON_OFFSET_FACTOR)
 GL_ENUM(0x803A,GL_RESCALE_NORMAL)
+GL_ENUM(0x803C,GL_ALPHA8_EXT)
+GL_ENUM(0x8040,GL_LUMINANCE8_EXT)
+GL_ENUM(0x8045,GL_LUMINANCE8_ALPHA8_EXT)
 GL_ENUM(0x8051,GL_RGB8_OES)
+GL_ENUM(0x8052,GL_RGB10_EXT)
 GL_ENUM(0x8056,GL_RGBA4_OES)
 GL_ENUM(0x8057,GL_RGB5_A1_OES)
 GL_ENUM(0x8058,GL_RGBA8_OES)
+GL_ENUM(0x8059,GL_RGB10_A2_EXT)
 GL_ENUM(0x8069,GL_TEXTURE_BINDING_2D)
 GL_ENUM(0x806A,GL_TEXTURE_BINDING_3D_OES)
 GL_ENUM(0x806F,GL_TEXTURE_3D_OES)
@@ -276,11 +288,28 @@
 GL_ENUM(0x8128,GL_POINT_FADE_THRESHOLD_SIZE)
 GL_ENUM(0x8129,GL_POINT_DISTANCE_ATTENUATION)
 GL_ENUM(0x812F,GL_CLAMP_TO_EDGE)
+GL_ENUM(0x813D,GL_TEXTURE_MAX_LEVEL_APPLE)
 GL_ENUM(0x8191,GL_GENERATE_MIPMAP)
 GL_ENUM(0x8192,GL_GENERATE_MIPMAP_HINT)
 GL_ENUM(0x81A5,GL_DEPTH_COMPONENT16_OES)
 GL_ENUM(0x81A6,GL_DEPTH_COMPONENT24_OES)
 GL_ENUM(0x81A7,GL_DEPTH_COMPONENT32_OES)
+GL_ENUM(0x8210,GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)
+GL_ENUM(0x8211,GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)
+GL_ENUM(0x8227,GL_RG_EXT)
+GL_ENUM(0x8229,GL_R8_EXT)
+GL_ENUM(0x822B,GL_RG8_EXT)
+GL_ENUM(0x822D,GL_R16F_EXT)
+GL_ENUM(0x822F,GL_RG16F_EXT)
+GL_ENUM(0x8252,GL_LOSE_CONTEXT_ON_RESET_EXT)
+GL_ENUM(0x8253,GL_GUILTY_CONTEXT_RESET_EXT)
+GL_ENUM(0x8254,GL_INNOCENT_CONTEXT_RESET_EXT)
+GL_ENUM(0x8255,GL_UNKNOWN_CONTEXT_RESET_EXT)
+GL_ENUM(0x8256,GL_RESET_NOTIFICATION_STRATEGY_EXT)
+GL_ENUM(0x8258,GL_PROGRAM_SEPARABLE_EXT)
+GL_ENUM(0x8259,GL_ACTIVE_PROGRAM_EXT)
+GL_ENUM(0x825A,GL_PROGRAM_PIPELINE_BINDING_EXT)
+GL_ENUM(0x8261,GL_NO_RESET_NOTIFICATION_EXT)
 GL_ENUM(0x8363,GL_UNSIGNED_SHORT_5_6_5)
 GL_ENUM(0x8365,GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT)
 GL_ENUM(0x8366,GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)
@@ -372,6 +401,8 @@
 GL_ENUM(0x8599,GL_OPERAND1_ALPHA)
 GL_ENUM(0x859A,GL_OPERAND2_ALPHA)
 GL_ENUM(0x85B5,GL_VERTEX_ARRAY_BINDING_OES)
+GL_ENUM(0x85BA,GL_UNSIGNED_SHORT_8_8_APPLE)
+GL_ENUM(0x85BB,GL_UNSIGNED_SHORT_8_8_REV_APPLE)
 GL_ENUM(0x8622,GL_VERTEX_ATTRIB_ARRAY_ENABLED)
 GL_ENUM(0x8623,GL_VERTEX_ATTRIB_ARRAY_SIZE)
 GL_ENUM(0x8624,GL_VERTEX_ATTRIB_ARRAY_STRIDE)
@@ -401,7 +432,34 @@
 GL_ENUM(0x8801,GL_STENCIL_BACK_FAIL)
 GL_ENUM(0x8802,GL_STENCIL_BACK_PASS_DEPTH_FAIL)
 GL_ENUM(0x8803,GL_STENCIL_BACK_PASS_DEPTH_PASS)
+GL_ENUM(0x8814,GL_RGBA32F_EXT)
+GL_ENUM(0x8815,GL_RGB32F_EXT)
+GL_ENUM(0x8816,GL_ALPHA32F_EXT)
+GL_ENUM(0x8818,GL_LUMINANCE32F_EXT)
+GL_ENUM(0x8819,GL_LUMINANCE_ALPHA32F_EXT)
+GL_ENUM(0x881A,GL_RGBA16F_EXT)
+GL_ENUM(0x881B,GL_RGB16F_EXT)
+GL_ENUM(0x881C,GL_ALPHA16F_EXT)
+GL_ENUM(0x881E,GL_LUMINANCE16F_EXT)
+GL_ENUM(0x881F,GL_LUMINANCE_ALPHA16F_EXT)
 GL_ENUM(0x8823,GL_WRITEONLY_RENDERING_QCOM)
+GL_ENUM(0x8824,GL_MAX_DRAW_BUFFERS_NV)
+GL_ENUM(0x8825,GL_DRAW_BUFFER0_NV)
+GL_ENUM(0x8826,GL_DRAW_BUFFER1_NV)
+GL_ENUM(0x8827,GL_DRAW_BUFFER2_NV)
+GL_ENUM(0x8828,GL_DRAW_BUFFER3_NV)
+GL_ENUM(0x8829,GL_DRAW_BUFFER4_NV)
+GL_ENUM(0x882A,GL_DRAW_BUFFER5_NV)
+GL_ENUM(0x882B,GL_DRAW_BUFFER6_NV)
+GL_ENUM(0x882C,GL_DRAW_BUFFER7_NV)
+GL_ENUM(0x882D,GL_DRAW_BUFFER8_NV)
+GL_ENUM(0x882E,GL_DRAW_BUFFER9_NV)
+GL_ENUM(0x882F,GL_DRAW_BUFFER10_NV)
+GL_ENUM(0x8830,GL_DRAW_BUFFER11_NV)
+GL_ENUM(0x8831,GL_DRAW_BUFFER12_NV)
+GL_ENUM(0x8832,GL_DRAW_BUFFER13_NV)
+GL_ENUM(0x8833,GL_DRAW_BUFFER14_NV)
+GL_ENUM(0x8834,GL_DRAW_BUFFER15_NV)
 GL_ENUM(0x883D,GL_BLEND_EQUATION_ALPHA_OES)
 GL_ENUM(0x8840,GL_MATRIX_PALETTE_OES)
 GL_ENUM(0x8842,GL_MAX_PALETTE_MATRICES_OES)
@@ -411,8 +469,14 @@
 GL_ENUM(0x8847,GL_MATRIX_INDEX_ARRAY_TYPE_OES)
 GL_ENUM(0x8848,GL_MATRIX_INDEX_ARRAY_STRIDE_OES)
 GL_ENUM(0x8849,GL_MATRIX_INDEX_ARRAY_POINTER_OES)
+GL_ENUM(0x884C,GL_TEXTURE_COMPARE_MODE_EXT)
+GL_ENUM(0x884D,GL_TEXTURE_COMPARE_FUNC_EXT)
+GL_ENUM(0x884E,GL_COMPARE_REF_TO_TEXTURE_EXT)
 GL_ENUM(0x8861,GL_POINT_SPRITE_OES)
 GL_ENUM(0x8862,GL_COORD_REPLACE_OES)
+GL_ENUM(0x8865,GL_CURRENT_QUERY_EXT)
+GL_ENUM(0x8866,GL_QUERY_RESULT_EXT)
+GL_ENUM(0x8867,GL_QUERY_RESULT_AVAILABLE_EXT)
 GL_ENUM(0x8869,GL_MAX_VERTEX_ATTRIBS)
 GL_ENUM(0x886A,GL_VERTEX_ATTRIB_ARRAY_NORMALIZED)
 GL_ENUM(0x8872,GL_MAX_TEXTURE_IMAGE_UNITS)
@@ -440,8 +504,12 @@
 GL_ENUM(0x898D,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES)
 GL_ENUM(0x898E,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES)
 GL_ENUM(0x898F,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES)
+GL_ENUM(0x8A1F,GL_RGB_422_APPLE)
+GL_ENUM(0x8A4F,GL_PROGRAM_PIPELINE_OBJECT_EXT)
 GL_ENUM(0x8B30,GL_FRAGMENT_SHADER)
 GL_ENUM(0x8B31,GL_VERTEX_SHADER)
+GL_ENUM(0x8B40,GL_PROGRAM_OBJECT_EXT)
+GL_ENUM(0x8B48,GL_SHADER_OBJECT_EXT)
 GL_ENUM(0x8B4C,GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
 GL_ENUM(0x8B4D,GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
 GL_ENUM(0x8B4F,GL_SHADER_TYPE)
@@ -461,6 +529,7 @@
 GL_ENUM(0x8B5E,GL_SAMPLER_2D)
 GL_ENUM(0x8B5F,GL_SAMPLER_3D_OES)
 GL_ENUM(0x8B60,GL_SAMPLER_CUBE)
+GL_ENUM(0x8B62,GL_SAMPLER_2D_SHADOW_EXT)
 GL_ENUM(0x8B80,GL_DELETE_STATUS)
 GL_ENUM(0x8B81,GL_COMPILE_STATUS)
 GL_ENUM(0x8B82,GL_LINK_STATUS)
@@ -520,6 +589,11 @@
 GL_ENUM(0x8C08,GL_FRAGMENT_ALPHA_MODULATE_IMG)
 GL_ENUM(0x8C09,GL_ADD_BLEND_IMG)
 GL_ENUM(0x8C0A,GL_SGX_BINARY_IMG)
+GL_ENUM(0x8C17,GL_UNSIGNED_NORMALIZED_EXT)
+GL_ENUM(0x8C2F,GL_ANY_SAMPLES_PASSED_EXT)
+GL_ENUM(0x8C40,GL_SRGB_EXT)
+GL_ENUM(0x8C42,GL_SRGB_ALPHA_EXT)
+GL_ENUM(0x8C43,GL_SRGB8_ALPHA8_EXT)
 GL_ENUM(0x8C92,GL_ATC_RGB_AMD)
 GL_ENUM(0x8C93,GL_ATC_RGBA_EXPLICIT_ALPHA_AMD)
 GL_ENUM(0x8CA3,GL_STENCIL_BACK_REF)
@@ -527,6 +601,10 @@
 GL_ENUM(0x8CA5,GL_STENCIL_BACK_WRITEMASK)
 GL_ENUM(0x8CA6,GL_FRAMEBUFFER_BINDING_OES)
 GL_ENUM(0x8CA7,GL_RENDERBUFFER_BINDING_OES)
+GL_ENUM(0x8CA8,GL_READ_FRAMEBUFFER_APPLE)
+GL_ENUM(0x8CA9,GL_DRAW_FRAMEBUFFER_APPLE)
+GL_ENUM(0x8CAA,GL_READ_FRAMEBUFFER_BINDING_APPLE)
+GL_ENUM(0x8CAB,GL_RENDERBUFFER_SAMPLES_APPLE)
 GL_ENUM(0x8CD0,GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES)
 GL_ENUM(0x8CD1,GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES)
 GL_ENUM(0x8CD2,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES)
@@ -538,7 +616,23 @@
 GL_ENUM(0x8CD9,GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES)
 GL_ENUM(0x8CDA,GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES)
 GL_ENUM(0x8CDD,GL_FRAMEBUFFER_UNSUPPORTED_OES)
+GL_ENUM(0x8CDF,GL_MAX_COLOR_ATTACHMENTS_NV)
 GL_ENUM(0x8CE0,GL_COLOR_ATTACHMENT0_OES)
+GL_ENUM(0x8CE1,GL_COLOR_ATTACHMENT1_NV)
+GL_ENUM(0x8CE2,GL_COLOR_ATTACHMENT2_NV)
+GL_ENUM(0x8CE3,GL_COLOR_ATTACHMENT3_NV)
+GL_ENUM(0x8CE4,GL_COLOR_ATTACHMENT4_NV)
+GL_ENUM(0x8CE5,GL_COLOR_ATTACHMENT5_NV)
+GL_ENUM(0x8CE6,GL_COLOR_ATTACHMENT6_NV)
+GL_ENUM(0x8CE7,GL_COLOR_ATTACHMENT7_NV)
+GL_ENUM(0x8CE8,GL_COLOR_ATTACHMENT8_NV)
+GL_ENUM(0x8CE9,GL_COLOR_ATTACHMENT9_NV)
+GL_ENUM(0x8CEA,GL_COLOR_ATTACHMENT10_NV)
+GL_ENUM(0x8CEB,GL_COLOR_ATTACHMENT11_NV)
+GL_ENUM(0x8CEC,GL_COLOR_ATTACHMENT12_NV)
+GL_ENUM(0x8CED,GL_COLOR_ATTACHMENT13_NV)
+GL_ENUM(0x8CEE,GL_COLOR_ATTACHMENT14_NV)
+GL_ENUM(0x8CEF,GL_COLOR_ATTACHMENT15_NV)
 GL_ENUM(0x8D00,GL_DEPTH_ATTACHMENT_OES)
 GL_ENUM(0x8D20,GL_STENCIL_ATTACHMENT_OES)
 GL_ENUM(0x8D40,GL_FRAMEBUFFER_OES)
@@ -555,6 +649,8 @@
 GL_ENUM(0x8D53,GL_RENDERBUFFER_ALPHA_SIZE_OES)
 GL_ENUM(0x8D54,GL_RENDERBUFFER_DEPTH_SIZE_OES)
 GL_ENUM(0x8D55,GL_RENDERBUFFER_STENCIL_SIZE_OES)
+GL_ENUM(0x8D56,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE)
+GL_ENUM(0x8D57,GL_MAX_SAMPLES_APPLE)
 GL_ENUM(0x8D60,GL_TEXTURE_GEN_STR_OES)
 GL_ENUM(0x8D61,GL_HALF_FLOAT_OES)
 GL_ENUM(0x8D62,GL_RGB565_OES)
@@ -563,6 +659,8 @@
 GL_ENUM(0x8D66,GL_SAMPLER_EXTERNAL_OES)
 GL_ENUM(0x8D67,GL_TEXTURE_BINDING_EXTERNAL_OES)
 GL_ENUM(0x8D68,GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES)
+GL_ENUM(0x8D6A,GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT)
+GL_ENUM(0x8D6C,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT)
 GL_ENUM(0x8DF0,GL_LOW_FLOAT)
 GL_ENUM(0x8DF1,GL_MEDIUM_FLOAT)
 GL_ENUM(0x8DF2,GL_HIGH_FLOAT)
@@ -586,9 +684,19 @@
 GL_ENUM(0x8ED5,GL_COVERAGE_ALL_FRAGMENTS_NV)
 GL_ENUM(0x8ED6,GL_COVERAGE_EDGE_FRAGMENTS_NV)
 GL_ENUM(0x8ED7,GL_COVERAGE_AUTOMATIC_NV)
+GL_ENUM(0x8F60,GL_MALI_SHADER_BINARY_ARM)
 GL_ENUM(0x8FA0,GL_PERFMON_GLOBAL_MODE_QCOM)
+GL_ENUM(0x8FC4,GL_SHADER_BINARY_VIV)
+GL_ENUM(0x90F3,GL_CONTEXT_ROBUST_ACCESS_EXT)
+GL_ENUM(0x912F,GL_TEXTURE_IMMUTABLE_FORMAT_EXT)
 GL_ENUM(0x9130,GL_SGX_PROGRAM_BINARY_IMG)
-GL_ENUM(0x9133,GL_RENDERBUFFER_SAMPLES_IMG)
-GL_ENUM(0x9134,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG)
-GL_ENUM(0x9135,GL_MAX_SAMPLES_IMG)
+GL_ENUM(0x9133,GL_RENDERBUFFER_SAMPLES_EXT)
+GL_ENUM(0x9134,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT)
+GL_ENUM(0x9135,GL_MAX_SAMPLES_EXT)
 GL_ENUM(0x9136,GL_TEXTURE_SAMPLES_IMG)
+GL_ENUM(0x9151,GL_BUFFER_OBJECT_EXT)
+GL_ENUM(0x9153,GL_QUERY_OBJECT_EXT)
+GL_ENUM(0x9154,GL_VERTEX_ARRAY_OBJECT_EXT)
+GL_ENUM(0x9250,GL_SHADER_BINARY_DMP)
+GL_ENUM(0x93A1,GL_BGRA8_EXT)
+GL_ENUM(0xFFFFFFFF,GL_ALL_SHADER_BITS_EXT)
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index 7ac88cd..8b1b389 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -37,7 +37,12 @@
 #endif
 #undef NELEM
 #define NELEM(x)                    (sizeof(x)/sizeof(*(x)))
-#define MAX_NUMBER_OF_GL_EXTENSIONS 64
+
+// maximum number of GL extensions that can be used simultaneously in
+// a given process. this limitation exists because we need to have
+// a static function for each extension and currently these static functions
+// are generated at compile time.
+#define MAX_NUMBER_OF_GL_EXTENSIONS 256
 
 
 #if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && __OPTIMIZE__
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
index bd8dda3..9be40cf 100755
--- a/opengl/libs/tools/glapigen
+++ b/opengl/libs/tools/glapigen
@@ -43,6 +43,9 @@
   if ($name eq "glEGLImageTargetRenderbufferStorageOES") {
     $prefix = "__";
   }
+  if ($name eq "glGetString") {
+    $prefix = "__";
+  }
   
   printf("%s API_ENTRY(%s%s)(%s)", $type, $prefix, $name, $args);
   
diff --git a/opengl/libs/trace.in b/opengl/libs/trace.in
index 3d492af..a5c5c84 100644
--- a/opengl/libs/trace.in
+++ b/opengl/libs/trace.in
@@ -1,13 +1,17 @@
+TRACE_GL_VOID(glActiveShaderProgramEXT, (GLuint pipeline, GLuint program), (pipeline, program), 2, "GLuint", pipeline, "GLuint", program)
 TRACE_GL_VOID(glActiveTexture, (GLenum texture), (texture), 1, "GLenum", texture)
 TRACE_GL_VOID(glAlphaFunc, (GLenum func, GLclampf ref), (func, ref), 2, "GLenum", func, "GLclampf", ref)
+TRACE_GL_VOID(glAlphaFuncQCOM, (GLenum func, GLclampf ref), (func, ref), 2, "GLenum", func, "GLclampf", ref)
 TRACE_GL_VOID(glAlphaFuncx, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref)
 TRACE_GL_VOID(glAlphaFuncxOES, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref)
 TRACE_GL_VOID(glAttachShader, (GLuint program, GLuint shader), (program, shader), 2, "GLuint", program, "GLuint", shader)
 TRACE_GL_VOID(glBeginPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor)
+TRACE_GL_VOID(glBeginQueryEXT, (GLenum target, GLuint id), (target, id), 2, "GLenum", target, "GLuint", id)
 TRACE_GL_VOID(glBindAttribLocation, (GLuint program, GLuint index, const GLchar* name), (program, index, name), 3, "GLuint", program, "GLuint", index, "const GLchar*", name)
 TRACE_GL_VOID(glBindBuffer, (GLenum target, GLuint buffer), (target, buffer), 2, "GLenum", target, "GLuint", buffer)
 TRACE_GL_VOID(glBindFramebuffer, (GLenum target, GLuint framebuffer), (target, framebuffer), 2, "GLenum", target, "GLuint", framebuffer)
 TRACE_GL_VOID(glBindFramebufferOES, (GLenum target, GLuint framebuffer), (target, framebuffer), 2, "GLenum", target, "GLuint", framebuffer)
+TRACE_GL_VOID(glBindProgramPipelineEXT, (GLuint pipeline), (pipeline), 1, "GLuint", pipeline)
 TRACE_GL_VOID(glBindRenderbuffer, (GLenum target, GLuint renderbuffer), (target, renderbuffer), 2, "GLenum", target, "GLuint", renderbuffer)
 TRACE_GL_VOID(glBindRenderbufferOES, (GLenum target, GLuint renderbuffer), (target, renderbuffer), 2, "GLenum", target, "GLuint", renderbuffer)
 TRACE_GL_VOID(glBindTexture, (GLenum target, GLuint texture), (target, texture), 2, "GLenum", target, "GLuint", texture)
@@ -20,6 +24,7 @@
 TRACE_GL_VOID(glBlendFunc, (GLenum sfactor, GLenum dfactor), (sfactor, dfactor), 2, "GLenum", sfactor, "GLenum", dfactor)
 TRACE_GL_VOID(glBlendFuncSeparate, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha), (srcRGB, dstRGB, srcAlpha, dstAlpha), 4, "GLenum", srcRGB, "GLenum", dstRGB, "GLenum", srcAlpha, "GLenum", dstAlpha)
 TRACE_GL_VOID(glBlendFuncSeparateOES, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha), (srcRGB, dstRGB, srcAlpha, dstAlpha), 4, "GLenum", srcRGB, "GLenum", dstRGB, "GLenum", srcAlpha, "GLenum", dstAlpha)
+TRACE_GL_VOID(glBlitFramebufferANGLE, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter), (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter), 10, "GLint", srcX0, "GLint", srcY0, "GLint", srcX1, "GLint", srcY1, "GLint", dstX0, "GLint", dstY0, "GLint", dstX1, "GLint", dstY1, "GLbitfield", mask, "GLenum", filter)
 TRACE_GL_VOID(glBufferData, (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage), (target, size, data, usage), 4, "GLenum", target, "GLsizeiptr", size, "const GLvoid *", data, "GLenum", usage)
 TRACE_GL_VOID(glBufferSubData, (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data), (target, offset, size, data), 4, "GLenum", target, "GLintptr", offset, "GLsizeiptr", size, "const GLvoid *", data)
 TRACE_GL(GLenum, glCheckFramebufferStatus, (GLenum target), (target), 1, "GLenum", target)
@@ -58,6 +63,7 @@
 TRACE_GL_VOID(glCoverageOperationNV, (GLenum operation), (operation), 1, "GLenum", operation)
 TRACE_GL(GLuint, glCreateProgram, (void), (), 0)
 TRACE_GL(GLuint, glCreateShader, (GLenum type), (type), 1, "GLenum", type)
+TRACE_GL(GLuint, glCreateShaderProgramvEXT, (GLenum type, GLsizei count, const GLchar **strings), (type, count, strings), 3, "GLenum", type, "GLsizei", count, "const GLchar **", strings)
 TRACE_GL_VOID(glCullFace, (GLenum mode), (mode), 1, "GLenum", mode)
 TRACE_GL_VOID(glCurrentPaletteMatrixOES, (GLuint matrixpaletteindex), (matrixpaletteindex), 1, "GLuint", matrixpaletteindex)
 TRACE_GL_VOID(glDeleteBuffers, (GLsizei n, const GLuint *buffers), (n, buffers), 2, "GLsizei", n, "const GLuint *", buffers)
@@ -66,6 +72,8 @@
 TRACE_GL_VOID(glDeleteFramebuffersOES, (GLsizei n, const GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "const GLuint*", framebuffers)
 TRACE_GL_VOID(glDeletePerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors)
 TRACE_GL_VOID(glDeleteProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glDeleteProgramPipelinesEXT, (GLsizei n, const GLuint *pipelines), (n, pipelines), 2, "GLsizei", n, "const GLuint *", pipelines)
+TRACE_GL_VOID(glDeleteQueriesEXT, (GLsizei n, const GLuint *ids), (n, ids), 2, "GLsizei", n, "const GLuint *", ids)
 TRACE_GL_VOID(glDeleteRenderbuffers, (GLsizei n, const GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "const GLuint*", renderbuffers)
 TRACE_GL_VOID(glDeleteRenderbuffersOES, (GLsizei n, const GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "const GLuint*", renderbuffers)
 TRACE_GL_VOID(glDeleteShader, (GLuint shader), (shader), 1, "GLuint", shader)
@@ -84,6 +92,7 @@
 TRACE_GL_VOID(glDisableVertexAttribArray, (GLuint index), (index), 1, "GLuint", index)
 TRACE_GL_VOID(glDiscardFramebufferEXT, (GLenum target, GLsizei numAttachments, const GLenum *attachments), (target, numAttachments, attachments), 3, "GLenum", target, "GLsizei", numAttachments, "const GLenum *", attachments)
 TRACE_GL_VOID(glDrawArrays, (GLenum mode, GLint first, GLsizei count), (mode, first, count), 3, "GLenum", mode, "GLint", first, "GLsizei", count)
+TRACE_GL_VOID(glDrawBuffersNV, (GLsizei n, const GLenum *bufs), (n, bufs), 2, "GLsizei", n, "const GLenum *", bufs)
 TRACE_GL_VOID(glDrawElements, (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices), (mode, count, type, indices), 4, "GLenum", mode, "GLsizei", count, "GLenum", type, "const GLvoid *", indices)
 TRACE_GL_VOID(glDrawTexfOES, (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height), (x, y, z, width, height), 5, "GLfloat", x, "GLfloat", y, "GLfloat", z, "GLfloat", width, "GLfloat", height)
 TRACE_GL_VOID(glDrawTexfvOES, (const GLfloat *coords), (coords), 1, "const GLfloat *", coords)
@@ -100,6 +109,7 @@
 TRACE_GL_VOID(glEnableDriverControlQCOM, (GLuint driverControl), (driverControl), 1, "GLuint", driverControl)
 TRACE_GL_VOID(glEnableVertexAttribArray, (GLuint index), (index), 1, "GLuint", index)
 TRACE_GL_VOID(glEndPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor)
+TRACE_GL_VOID(glEndQueryEXT, (GLenum target), (target), 1, "GLenum", target)
 TRACE_GL_VOID(glEndTilingQCOM, (GLbitfield preserveMask), (preserveMask), 1, "GLbitfield", preserveMask)
 TRACE_GL_VOID(glExtGetBufferPointervQCOM, (GLenum target, GLvoid **params), (target, params), 2, "GLenum", target, "GLvoid **", params)
 TRACE_GL_VOID(glExtGetBuffersQCOM, (GLuint *buffers, GLint maxBuffers, GLint *numBuffers), (buffers, maxBuffers, numBuffers), 3, "GLuint *", buffers, "GLint", maxBuffers, "GLint *", numBuffers)
@@ -125,6 +135,7 @@
 TRACE_GL_VOID(glFramebufferRenderbuffer, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer), (target, attachment, renderbuffertarget, renderbuffer), 4, "GLenum", target, "GLenum", attachment, "GLenum", renderbuffertarget, "GLuint", renderbuffer)
 TRACE_GL_VOID(glFramebufferRenderbufferOES, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer), (target, attachment, renderbuffertarget, renderbuffer), 4, "GLenum", target, "GLenum", attachment, "GLenum", renderbuffertarget, "GLuint", renderbuffer)
 TRACE_GL_VOID(glFramebufferTexture2D, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level), (target, attachment, textarget, texture, level), 5, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level)
+TRACE_GL_VOID(glFramebufferTexture2DMultisampleEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples), (target, attachment, textarget, texture, level, samples), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLsizei", samples)
 TRACE_GL_VOID(glFramebufferTexture2DMultisampleIMG, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples), (target, attachment, textarget, texture, level, samples), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLsizei", samples)
 TRACE_GL_VOID(glFramebufferTexture2DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level), (target, attachment, textarget, texture, level), 5, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level)
 TRACE_GL_VOID(glFramebufferTexture3DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset), (target, attachment, textarget, texture, level, zoffset), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLint", zoffset)
@@ -138,6 +149,8 @@
 TRACE_GL_VOID(glGenFramebuffers, (GLsizei n, GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "GLuint*", framebuffers)
 TRACE_GL_VOID(glGenFramebuffersOES, (GLsizei n, GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "GLuint*", framebuffers)
 TRACE_GL_VOID(glGenPerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors)
+TRACE_GL_VOID(glGenProgramPipelinesEXT, (GLsizei n, GLuint *pipelines), (n, pipelines), 2, "GLsizei", n, "GLuint *", pipelines)
+TRACE_GL_VOID(glGenQueriesEXT, (GLsizei n, GLuint *ids), (n, ids), 2, "GLsizei", n, "GLuint *", ids)
 TRACE_GL_VOID(glGenRenderbuffers, (GLsizei n, GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "GLuint*", renderbuffers)
 TRACE_GL_VOID(glGenRenderbuffersOES, (GLsizei n, GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "GLuint*", renderbuffers)
 TRACE_GL_VOID(glGenTextures, (GLsizei n, GLuint *textures), (n, textures), 2, "GLsizei", n, "GLuint *", textures)
@@ -164,6 +177,7 @@
 TRACE_GL_VOID(glGetFloatv, (GLenum pname, GLfloat *params), (pname, params), 2, "GLenum", pname, "GLfloat *", params)
 TRACE_GL_VOID(glGetFramebufferAttachmentParameteriv, (GLenum target, GLenum attachment, GLenum pname, GLint* params), (target, attachment, pname, params), 4, "GLenum", target, "GLenum", attachment, "GLenum", pname, "GLint*", params)
 TRACE_GL_VOID(glGetFramebufferAttachmentParameterivOES, (GLenum target, GLenum attachment, GLenum pname, GLint* params), (target, attachment, pname, params), 4, "GLenum", target, "GLenum", attachment, "GLenum", pname, "GLint*", params)
+TRACE_GL(GLenum, glGetGraphicsResetStatusEXT, (void), (), 0)
 TRACE_GL_VOID(glGetIntegerv, (GLenum pname, GLint *params), (pname, params), 2, "GLenum", pname, "GLint *", params)
 TRACE_GL_VOID(glGetLightfv, (GLenum light, GLenum pname, GLfloat *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfloat *", params)
 TRACE_GL_VOID(glGetLightxv, (GLenum light, GLenum pname, GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfixed *", params)
@@ -171,6 +185,7 @@
 TRACE_GL_VOID(glGetMaterialfv, (GLenum face, GLenum pname, GLfloat *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfloat *", params)
 TRACE_GL_VOID(glGetMaterialxv, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params)
 TRACE_GL_VOID(glGetMaterialxvOES, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetObjectLabelEXT, (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label), (type, object, bufSize, length, label), 5, "GLenum", type, "GLuint", object, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", label)
 TRACE_GL_VOID(glGetPerfMonitorCounterDataAMD, (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten), (monitor, pname, dataSize, data, bytesWritten), 5, "GLuint", monitor, "GLenum", pname, "GLsizei", dataSize, "GLuint *", data, "GLint *", bytesWritten)
 TRACE_GL_VOID(glGetPerfMonitorCounterInfoAMD, (GLuint group, GLuint counter, GLenum pname, GLvoid *data), (group, counter, pname, data), 4, "GLuint", group, "GLuint", counter, "GLenum", pname, "GLvoid *", data)
 TRACE_GL_VOID(glGetPerfMonitorCounterStringAMD, (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString), (group, counter, bufSize, length, counterString), 5, "GLuint", group, "GLuint", counter, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", counterString)
@@ -180,7 +195,11 @@
 TRACE_GL_VOID(glGetPointerv, (GLenum pname, GLvoid **params), (pname, params), 2, "GLenum", pname, "GLvoid **", params)
 TRACE_GL_VOID(glGetProgramBinaryOES, (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary), (program, bufSize, length, binaryFormat, binary), 5, "GLuint", program, "GLsizei", bufSize, "GLsizei *", length, "GLenum *", binaryFormat, "GLvoid *", binary)
 TRACE_GL_VOID(glGetProgramInfoLog, (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog), (program, bufsize, length, infolog), 4, "GLuint", program, "GLsizei", bufsize, "GLsizei*", length, "GLchar*", infolog)
+TRACE_GL_VOID(glGetProgramPipelineInfoLogEXT, (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog), (pipeline, bufSize, length, infoLog), 4, "GLuint", pipeline, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", infoLog)
+TRACE_GL_VOID(glGetProgramPipelineivEXT, (GLuint pipeline, GLenum pname, GLint *params), (pipeline, pname, params), 3, "GLuint", pipeline, "GLenum", pname, "GLint *", params)
 TRACE_GL_VOID(glGetProgramiv, (GLuint program, GLenum pname, GLint* params), (program, pname, params), 3, "GLuint", program, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetQueryObjectuivEXT, (GLuint id, GLenum pname, GLuint *params), (id, pname, params), 3, "GLuint", id, "GLenum", pname, "GLuint *", params)
+TRACE_GL_VOID(glGetQueryivEXT, (GLenum target, GLenum pname, GLint *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint *", params)
 TRACE_GL_VOID(glGetRenderbufferParameteriv, (GLenum target, GLenum pname, GLint* params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint*", params)
 TRACE_GL_VOID(glGetRenderbufferParameterivOES, (GLenum target, GLenum pname, GLint* params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint*", params)
 TRACE_GL_VOID(glGetShaderInfoLog, (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog), (shader, bufsize, length, infolog), 4, "GLuint", shader, "GLsizei", bufsize, "GLsizei*", length, "GLchar*", infolog)
@@ -205,18 +224,24 @@
 TRACE_GL_VOID(glGetVertexAttribPointerv, (GLuint index, GLenum pname, GLvoid** pointer), (index, pname, pointer), 3, "GLuint", index, "GLenum", pname, "GLvoid**", pointer)
 TRACE_GL_VOID(glGetVertexAttribfv, (GLuint index, GLenum pname, GLfloat* params), (index, pname, params), 3, "GLuint", index, "GLenum", pname, "GLfloat*", params)
 TRACE_GL_VOID(glGetVertexAttribiv, (GLuint index, GLenum pname, GLint* params), (index, pname, params), 3, "GLuint", index, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetnUniformfvEXT, (GLuint program, GLint location, GLsizei bufSize, float *params), (program, location, bufSize, params), 4, "GLuint", program, "GLint", location, "GLsizei", bufSize, "float *", params)
+TRACE_GL_VOID(glGetnUniformivEXT, (GLuint program, GLint location, GLsizei bufSize, GLint *params), (program, location, bufSize, params), 4, "GLuint", program, "GLint", location, "GLsizei", bufSize, "GLint *", params)
 TRACE_GL_VOID(glHint, (GLenum target, GLenum mode), (target, mode), 2, "GLenum", target, "GLenum", mode)
+TRACE_GL_VOID(glInsertEventMarkerEXT, (GLsizei length, const GLchar *marker), (length, marker), 2, "GLsizei", length, "const GLchar *", marker)
 TRACE_GL(GLboolean, glIsBuffer, (GLuint buffer), (buffer), 1, "GLuint", buffer)
 TRACE_GL(GLboolean, glIsEnabled, (GLenum cap), (cap), 1, "GLenum", cap)
 TRACE_GL(GLboolean, glIsFenceNV, (GLuint fence), (fence), 1, "GLuint", fence)
 TRACE_GL(GLboolean, glIsFramebuffer, (GLuint framebuffer), (framebuffer), 1, "GLuint", framebuffer)
 TRACE_GL(GLboolean, glIsFramebufferOES, (GLuint framebuffer), (framebuffer), 1, "GLuint", framebuffer)
 TRACE_GL(GLboolean, glIsProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL(GLboolean, glIsProgramPipelineEXT, (GLuint pipeline), (pipeline), 1, "GLuint", pipeline)
+TRACE_GL(GLboolean, glIsQueryEXT, (GLuint id), (id), 1, "GLuint", id)
 TRACE_GL(GLboolean, glIsRenderbuffer, (GLuint renderbuffer), (renderbuffer), 1, "GLuint", renderbuffer)
 TRACE_GL(GLboolean, glIsRenderbufferOES, (GLuint renderbuffer), (renderbuffer), 1, "GLuint", renderbuffer)
 TRACE_GL(GLboolean, glIsShader, (GLuint shader), (shader), 1, "GLuint", shader)
 TRACE_GL(GLboolean, glIsTexture, (GLuint texture), (texture), 1, "GLuint", texture)
 TRACE_GL(GLboolean, glIsVertexArrayOES, (GLuint array), (array), 1, "GLuint", array)
+TRACE_GL_VOID(glLabelObjectEXT, (GLenum type, GLuint object, GLsizei length, const GLchar *label), (type, object, length, label), 4, "GLenum", type, "GLuint", object, "GLsizei", length, "const GLchar *", label)
 TRACE_GL_VOID(glLightModelf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param)
 TRACE_GL_VOID(glLightModelfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params)
 TRACE_GL_VOID(glLightModelx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
@@ -278,15 +303,43 @@
 TRACE_GL_VOID(glPolygonOffset, (GLfloat factor, GLfloat units), (factor, units), 2, "GLfloat", factor, "GLfloat", units)
 TRACE_GL_VOID(glPolygonOffsetx, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units)
 TRACE_GL_VOID(glPolygonOffsetxOES, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units)
+TRACE_GL_VOID(glPopGroupMarkerEXT, (void), (), 0)
 TRACE_GL_VOID(glPopMatrix, (void), (), 0)
 TRACE_GL_VOID(glProgramBinaryOES, (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length), (program, binaryFormat, binary, length), 4, "GLuint", program, "GLenum", binaryFormat, "const GLvoid *", binary, "GLint", length)
+TRACE_GL_VOID(glProgramParameteriEXT, (GLuint program, GLenum pname, GLint value), (program, pname, value), 3, "GLuint", program, "GLenum", pname, "GLint", value)
+TRACE_GL_VOID(glProgramUniform1fEXT, (GLuint program, GLint location, GLfloat x), (program, location, x), 3, "GLuint", program, "GLint", location, "GLfloat", x)
+TRACE_GL_VOID(glProgramUniform1fvEXT, (GLuint program, GLint location, GLsizei count, const GLfloat *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniform1iEXT, (GLuint program, GLint location, GLint x), (program, location, x), 3, "GLuint", program, "GLint", location, "GLint", x)
+TRACE_GL_VOID(glProgramUniform1ivEXT, (GLuint program, GLint location, GLsizei count, const GLint *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLint *", value)
+TRACE_GL_VOID(glProgramUniform2fEXT, (GLuint program, GLint location, GLfloat x, GLfloat y), (program, location, x, y), 4, "GLuint", program, "GLint", location, "GLfloat", x, "GLfloat", y)
+TRACE_GL_VOID(glProgramUniform2fvEXT, (GLuint program, GLint location, GLsizei count, const GLfloat *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniform2iEXT, (GLuint program, GLint location, GLint x, GLint y), (program, location, x, y), 4, "GLuint", program, "GLint", location, "GLint", x, "GLint", y)
+TRACE_GL_VOID(glProgramUniform2ivEXT, (GLuint program, GLint location, GLsizei count, const GLint *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLint *", value)
+TRACE_GL_VOID(glProgramUniform3fEXT, (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z), (program, location, x, y, z), 5, "GLuint", program, "GLint", location, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glProgramUniform3fvEXT, (GLuint program, GLint location, GLsizei count, const GLfloat *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniform3iEXT, (GLuint program, GLint location, GLint x, GLint y, GLint z), (program, location, x, y, z), 5, "GLuint", program, "GLint", location, "GLint", x, "GLint", y, "GLint", z)
+TRACE_GL_VOID(glProgramUniform3ivEXT, (GLuint program, GLint location, GLsizei count, const GLint *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLint *", value)
+TRACE_GL_VOID(glProgramUniform4fEXT, (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w), (program, location, x, y, z, w), 6, "GLuint", program, "GLint", location, "GLfloat", x, "GLfloat", y, "GLfloat", z, "GLfloat", w)
+TRACE_GL_VOID(glProgramUniform4fvEXT, (GLuint program, GLint location, GLsizei count, const GLfloat *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniform4iEXT, (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w), (program, location, x, y, z, w), 6, "GLuint", program, "GLint", location, "GLint", x, "GLint", y, "GLint", z, "GLint", w)
+TRACE_GL_VOID(glProgramUniform4ivEXT, (GLuint program, GLint location, GLsizei count, const GLint *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLint *", value)
+TRACE_GL_VOID(glProgramUniformMatrix2fvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value), (program, location, count, transpose, value), 5, "GLuint", program, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniformMatrix3fvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value), (program, location, count, transpose, value), 5, "GLuint", program, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniformMatrix4fvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value), (program, location, count, transpose, value), 5, "GLuint", program, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat *", value)
+TRACE_GL_VOID(glPushGroupMarkerEXT, (GLsizei length, const GLchar *marker), (length, marker), 2, "GLsizei", length, "const GLchar *", marker)
 TRACE_GL_VOID(glPushMatrix, (void), (), 0)
 TRACE_GL(GLbitfield, glQueryMatrixxOES, (GLfixed mantissa[16], GLint exponent[16]), (mantissa, exponent), 2, "GLfixed", mantissa, "GLint", exponent)
+TRACE_GL_VOID(glReadBufferNV, (GLenum mode), (mode), 1, "GLenum", mode)
 TRACE_GL_VOID(glReadPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels), (x, y, width, height, format, type, pixels), 7, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height, "GLenum", format, "GLenum", type, "GLvoid *", pixels)
+TRACE_GL_VOID(glReadnPixelsEXT, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data), (x, y, width, height, format, type, bufSize, data), 8, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height, "GLenum", format, "GLenum", type, "GLsizei", bufSize, "void *", data)
 TRACE_GL_VOID(glReleaseShaderCompiler, (void), (), 0)
 TRACE_GL_VOID(glRenderbufferStorage, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), (target, internalformat, width, height), 4, "GLenum", target, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRenderbufferStorageMultisampleANGLE, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRenderbufferStorageMultisampleAPPLE, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRenderbufferStorageMultisampleEXT, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
 TRACE_GL_VOID(glRenderbufferStorageMultisampleIMG, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
 TRACE_GL_VOID(glRenderbufferStorageOES, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), (target, internalformat, width, height), 4, "GLenum", target, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glResolveMultisampleFramebufferAPPLE, (void), (), 0)
 TRACE_GL_VOID(glRotatef, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z), (angle, x, y, z), 4, "GLfloat", angle, "GLfloat", x, "GLfloat", y, "GLfloat", z)
 TRACE_GL_VOID(glRotatex, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z)
 TRACE_GL_VOID(glRotatexOES, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z)
@@ -335,8 +388,14 @@
 TRACE_GL_VOID(glTexParameterxOES, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
 TRACE_GL_VOID(glTexParameterxv, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
 TRACE_GL_VOID(glTexParameterxvOES, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexStorage1DEXT, (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width), (target, levels, internalformat, width), 4, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width)
+TRACE_GL_VOID(glTexStorage2DEXT, (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height), (target, levels, internalformat, width, height), 5, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glTexStorage3DEXT, (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth), (target, levels, internalformat, width, height, depth), 6, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth)
 TRACE_GL_VOID(glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels), (target, level, xoffset, yoffset, width, height, format, type, pixels), 9, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLsizei", width, "GLsizei", height, "GLenum", format, "GLenum", type, "const GLvoid *", pixels)
 TRACE_GL_VOID(glTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLenum", type, "const GLvoid*", pixels)
+TRACE_GL_VOID(glTextureStorage1DEXT, (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width), (texture, target, levels, internalformat, width), 5, "GLuint", texture, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width)
+TRACE_GL_VOID(glTextureStorage2DEXT, (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height), (texture, target, levels, internalformat, width, height), 6, "GLuint", texture, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glTextureStorage3DEXT, (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth), (texture, target, levels, internalformat, width, height, depth), 7, "GLuint", texture, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth)
 TRACE_GL_VOID(glTranslatef, (GLfloat x, GLfloat y, GLfloat z), (x, y, z), 3, "GLfloat", x, "GLfloat", y, "GLfloat", z)
 TRACE_GL_VOID(glTranslatex, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
 TRACE_GL_VOID(glTranslatexOES, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
@@ -361,7 +420,9 @@
 TRACE_GL_VOID(glUniformMatrix4fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value), (location, count, transpose, value), 4, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat*", value)
 TRACE_GL(GLboolean, glUnmapBufferOES, (GLenum target), (target), 1, "GLenum", target)
 TRACE_GL_VOID(glUseProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glUseProgramStagesEXT, (GLuint pipeline, GLbitfield stages, GLuint program), (pipeline, stages, program), 3, "GLuint", pipeline, "GLbitfield", stages, "GLuint", program)
 TRACE_GL_VOID(glValidateProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glValidateProgramPipelineEXT, (GLuint pipeline), (pipeline), 1, "GLuint", pipeline)
 TRACE_GL_VOID(glVertexAttrib1f, (GLuint indx, GLfloat x), (indx, x), 2, "GLuint", indx, "GLfloat", x)
 TRACE_GL_VOID(glVertexAttrib1fv, (GLuint indx, const GLfloat* values), (indx, values), 2, "GLuint", indx, "const GLfloat*", values)
 TRACE_GL_VOID(glVertexAttrib2f, (GLuint indx, GLfloat x, GLfloat y), (indx, x, y), 3, "GLuint", indx, "GLfloat", x, "GLfloat", y)
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 4ea2c31..3beaac9 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -43,6 +43,7 @@
     <bool name="assisted_gps_enabled">true</bool>
     <!--  0 == mobile, 1 == wifi. -->
     <integer name="def_network_preference">1</integer>
+    <bool name="def_netstats_enabled">true</bool>
     <bool name="def_usb_mass_storage_enabled">true</bool>
     <bool name="def_wifi_on">false</bool>
     <bool name="def_networks_available_notification_on">true</bool>
@@ -70,6 +71,8 @@
     <integer name="def_lockscreen_sounds_enabled">1</integer>
     <string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
     <string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
+    <bool name="def_lockscreen_disabled">false</bool>
+    <bool name="def_device_provisioned">false</bool>
 
     <!-- Notifications use ringer volume -->
     <bool name="def_notifications_use_ring_volume">true</bool>
@@ -141,4 +144,8 @@
     <bool name="def_dtmf_tones_enabled">true</bool>
     <!-- Default for UI touch sounds enabled -->
     <bool name="def_sound_effects_enabled">true</bool>
+
+    <!-- Development settings -->
+    <bool name="def_stay_on_while_plugged_in">false</bool>
+
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 6e9ea52..882aa66 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -63,7 +63,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 75;
+    private static final int DATABASE_VERSION = 76;
 
     private Context mContext;
 
@@ -1006,6 +1006,29 @@
             }
             upgradeVersion = 75;
         }
+        if (upgradeVersion == 75) {
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            Cursor c = null;
+            try {
+                c = db.query("secure", new String[] {"_id", "value"},
+                        "name='lockscreen.disabled'",
+                        null, null, null, null);
+                // only set default if it has not yet been set
+                if (c == null || c.getCount() == 0) {
+                    stmt = db.compileStatement("INSERT INTO system(name,value)"
+                            + " VALUES(?,?);");
+                    loadBooleanSetting(stmt, Settings.System.LOCKSCREEN_DISABLED,
+                            R.bool.def_lockscreen_disabled);
+                }
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (c != null) c.close();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 76;
+        }
 
         // *** Remember to update DATABASE_VERSION above!
 
@@ -1352,7 +1375,9 @@
             loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
                     R.bool.def_dim_screen);
             loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN,
-                    "1".equals(SystemProperties.get("ro.kernel.qemu")) ? 1 : 0);
+                    ("1".equals(SystemProperties.get("ro.kernel.qemu")) ||
+                        mContext.getResources().getBoolean(R.bool.def_stay_on_while_plugged_in))
+                     ? 1 : 0);
             loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
                     R.integer.def_screen_off_timeout);
     
@@ -1568,6 +1593,15 @@
 
             loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
                     R.string.def_accessibility_screen_reader_url);
+
+            loadBooleanSetting(stmt, Settings.System.LOCKSCREEN_DISABLED,
+                    R.bool.def_lockscreen_disabled);
+
+            loadBooleanSetting(stmt, Settings.Secure.DEVICE_PROVISIONED,
+                    R.bool.def_device_provisioned);
+
+            loadBooleanSetting(stmt, Settings.Secure.NETSTATS_ENABLED,
+                    R.bool.def_netstats_enabled);
         } finally {
             if (stmt != null) stmt.close();
         }
diff --git a/packages/SystemUI/lint.xml b/packages/SystemUI/lint.xml
new file mode 100644
index 0000000..59a7109
--- /dev/null
+++ b/packages/SystemUI/lint.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<lint>
+    <issue id="PrivateResource" severity="ignore" />
+</lint>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index 2d76455..aa27861 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -58,6 +58,7 @@
             android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
             android:scaleType="centerInside"
             android:adjustViewBounds="true"
+            android:visibility="invisible"
         />
 
         <TextView android:id="@+id/app_label"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index b653fcd..bc389f9 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -81,6 +81,7 @@
             android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
             android:scaleType="centerInside"
             android:adjustViewBounds="true"
+            android:visibility="invisible"
         />
 
         <TextView android:id="@+id/app_description"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
index ef95936..b985aaf 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
@@ -63,6 +63,7 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:layout_gravity="center_vertical"
+                android:paddingRight="6dp"
                 >
 
                 <ImageView
@@ -87,7 +88,6 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:paddingRight="12dp"
-                android:paddingLeft="6dp"
                 android:singleLine="true"
                 android:ellipsize="end"
                 android:text="@string/status_bar_settings_settings_button"
@@ -99,6 +99,7 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:layout_gravity="center_vertical"
+                android:paddingRight="6dp"
                 >
 
                 <ImageView
@@ -122,7 +123,6 @@
                 android:layout_gravity="left|center_vertical"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:paddingLeft="6dp"
                 android:paddingRight="12dp"
                 android:singleLine="true"
                 android:ellipsize="end"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index cb26db00..333fcda 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -65,6 +65,7 @@
         android:maxHeight="@dimen/status_bar_recents_app_icon_max_height"
         android:scaleType="centerInside"
         android:adjustViewBounds="true"
+        android:visibility="invisible"
     />
 
 
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index a6c64ad..d083467 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -101,7 +101,12 @@
     <string name="accessibility_wifi_one_bar" msgid="6854947280074467207">"Wi-Fi, адзiн слупок."</string>
     <string name="accessibility_wifi_two_bars" msgid="3344340012058984348">"Wi-Fi, два слупкi."</string>
     <string name="accessibility_wifi_three_bars" msgid="928322805193265041">"Wi-Fi, тры слупкi."</string>
-    <string name="accessibility_wifi_signal_full" msgid="4826278754383492058">"Моцны сiгнал Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="1275764416228473932">"Поўны сігнал Wi-Fi."</string>
+    <string name="accessibility_no_wimax" msgid="4329180129727630368">"Няма сiгналу WiMAX."</string>
+    <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"Адзiн слупок сiгналу WiMAX."</string>
+    <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"Два слупкi сiгналу WiMAX."</string>
+    <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"Тры слупкi сiгналу WiMAX."</string>
+    <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"Моцны сiгнал WiMAX."</string>
     <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
     <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
     <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string>
@@ -135,4 +140,5 @@
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Пошук GPS"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Месца задана праз GPS"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Выдалiць усе апавяшчэннi."</string>
+    <string name="dreams_dock_launcher" msgid="3541196417659166245">"Актывацыя экраннай застаўкі"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index e84f40f..ab4eeb4 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -133,7 +133,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-Daten deaktiviert"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobile Daten deaktiviert"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Daten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Sie haben die angegebenen Grenze für die Datennutzung erreicht."\n\n"Wenn Sie die Datennutzung erneut aktivieren, berechnet Ihr Mobilfunkanbieter unter Umständen zusätzliche Gebühren."</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Sie haben die angegebenen Grenze für den Datenverbrauch erreicht."\n\n"Wenn Sie die Datennutzung erneut aktivieren, berechnet Ihr Mobilfunkanbieter unter Umständen zusätzliche Gebühren."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Daten erneut aktivieren"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
diff --git a/packages/SystemUI/res/values-es-rUS-large/strings.xml b/packages/SystemUI/res/values-es-rUS-large/strings.xml
index 3f96e87..dd44b28 100644
--- a/packages/SystemUI/res/values-es-rUS-large/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS-large/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Borrar todas"</string>
+    <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Eliminar todas"</string>
     <string name="notifications_off_title" msgid="1860117696034775851">"Notificaciones desactivadas"</string>
     <string name="notifications_off_text" msgid="1439152806320786912">"Toca aquí para volver a activar las notificaciones."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 85818ae..a700908 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -20,7 +20,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="7164937344850004466">"IU del sistema"</string>
-    <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
+    <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Eliminar"</string>
     <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"No molestar"</string>
     <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificaciones"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminar de la lista"</string>
@@ -122,7 +122,7 @@
     <skip />
     <string name="accessibility_settings_button" msgid="799583911231893380">"Configuración del sistema"</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificaciones"</string>
-    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Borrar notificación"</string>
+    <string name="accessibility_remove_notification" msgid="3603099514902182350">"Eliminar notificación"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS habilitado"</string>
     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Adquisición de GPS"</string>
     <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter habilitado"</string>
@@ -133,12 +133,12 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datos de 4G inhabilitados"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Se inhabilitaron los datos móviles"</string>
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Datos inhabilitados"</string>
-    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Alcanzaste el límite de uso de datos especificado."\n\n"Puede que tu operador te cobre por volver a habilitar datos."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Volver a habilitar datos"</string>
+    <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Alcanzaste el límite de uso de datos especificado."\n\n"Puede que tu operador te cobre por volver a activar datos."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Volver a activar datos"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string>
-    <string name="accessibility_clear_all" msgid="5235938559247164925">"Borrar todas las notificaciones"</string>
+    <string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas las notificaciones"</string>
     <string name="dreams_dock_launcher" msgid="3541196417659166245">"Activar el protector de pantalla"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 943b8ca..16bb040 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -65,7 +65,7 @@
     <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Kuvatõmmise salvestamine ..."</string>
     <string name="screenshot_saving_title" msgid="8242282144535555697">"Kuvatõmmise salvestamine ..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"Kuvatõmmist salvestatakse."</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"Kuvatõmmis on jäädvustatud."</string>
+    <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekraanipilt on jäädvustatud."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Puudutage kuvatõmmise vaatamiseks."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Kuvatõmmist ei saanud jäädvustada."</string>
     <string name="screenshot_failed_text" msgid="8134011269572415402">"Kuvatõmmist ei saa salvestada. Mäluseade võib olla kasutuses."</string>
@@ -101,7 +101,12 @@
     <string name="accessibility_wifi_one_bar" msgid="6854947280074467207">"WiFi signaal: üks post."</string>
     <string name="accessibility_wifi_two_bars" msgid="3344340012058984348">"WiFi signaal: kaks posti."</string>
     <string name="accessibility_wifi_three_bars" msgid="928322805193265041">"WiFi signaal: kolm posti."</string>
-    <string name="accessibility_wifi_signal_full" msgid="4826278754383492058">"WiFi signaal on täis."</string>
+    <string name="accessibility_wifi_signal_full" msgid="1275764416228473932">"WiFi-signaal on tugev."</string>
+    <string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX-i pole."</string>
+    <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX-i on üks riba."</string>
+    <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX-i on kaks riba."</string>
+    <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX-i on kolm riba."</string>
+    <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX-i signaal on tugev."</string>
     <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
     <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
     <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3,5G"</string>
@@ -133,4 +138,5 @@
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-i otsimine"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-i määratud asukoht"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Kustuta kõik teatised."</string>
+    <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiveeri ekraanisäästja"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 545d54e..dec4def 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -115,7 +115,7 @@
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Sem SIM."</string>
-    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Vínculo Bluetooth."</string>
+    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Tethering Bluetooth."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Modo de avião."</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for accessibility_battery_level (7451474187113371965) -->
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 2106b89..983df47 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -39,8 +39,10 @@
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nagins avis"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actual"</string>
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Avis"</string>
-    <!-- outdated translation 7923774589611311406 -->     <string name="battery_low_title" msgid="2783104807551211639">"Connectar il chargiabattarias"</string>
-    <!-- outdated translation 7388781709819722764 -->     <string name="battery_low_subtitle" msgid="1752040062087829196">"L\'accu è prest vid."</string>
+    <!-- no translation found for battery_low_title (2783104807551211639) -->
+    <skip />
+    <!-- no translation found for battery_low_subtitle (1752040062087829196) -->
+    <skip />
     <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
     <skip />
     <!-- no translation found for invalid_charger (4549105996740522523) -->
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 17330b1..963976d 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -36,7 +36,7 @@
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string>
     <string name="battery_low_title" msgid="2783104807551211639">"Подключите зарядное устройство"</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея разряжена."</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается."\n"Используйте только зарядное устройство из комплекта поставки."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Расход заряда батареи"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 3843ea9..70e29eb 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -26,7 +26,7 @@
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Ondoa kwenye orodha"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Taarifa za programu-matumizi"</string>
     <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Hakuna programu za sasa"</string>
-    <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ondosha programu za hivi karibuni"</string>
+    <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ondosha prog za hivi karibuni"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for status_bar_accessibility_recent_apps:other (1040784359794890744) -->
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Hakuna arifa"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 39b428a..0249e89 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -36,7 +36,7 @@
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Izaziso"</string>
     <string name="battery_low_title" msgid="2783104807551211639">"Xhuma ishaja."</string>
     <string name="battery_low_subtitle" msgid="1752040062087829196">"Ibhetri iya ngokuphela."</string>
-    <string name="battery_low_percent_format" msgid="1077244949318261761">"okusele okungu-<xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+    <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> okusele"</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Ukushaja i-USB akusekelwe."\n"Sebenzisa kuphela ishaja enikeziwe."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Ukusebenzisa ibhetri"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Izilungiselelo"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 14ce266..cd8bd4e 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -236,6 +236,10 @@
             public void onAnimationEnd(Animator animation) {
                 mCallback.onChildDismissed(view);
                 animView.setLayerType(View.LAYER_TYPE_NONE, null);
+                // Restore the alpha/translation parameters to what they were before swiping
+                // (for when these items are recycled)
+                animView.setAlpha(1f);
+                setTranslation(animView, 0f);
             }
         });
         anim.addUpdateListener(new AnimatorUpdateListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
index 723e338..888b76e 100644
--- a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
@@ -77,7 +77,7 @@
         final INetworkPolicyManager policyService = INetworkPolicyManager.Stub.asInterface(
                 ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
         try {
-            policyService.snoozePolicy(template);
+            policyService.snoozeLimit(template);
         } catch (RemoteException e) {
             Slog.w(TAG, "problem snoozing network policy", e);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index ad38a11..f8a4592 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -134,6 +134,7 @@
 
     void jumpTo(boolean appearing) {
         mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
+        mScrimView.getBackground().setAlpha(appearing ? 255 : 0);
     }
 
     public void setPanelHeight(int h) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index dcda9c2..92f4ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -16,12 +16,6 @@
 
 package com.android.systemui.recent;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -36,15 +30,17 @@
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Process;
-import android.os.SystemClock;
-import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.LruCache;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.tablet.TabletStatusBar;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
 public class RecentTasksLoader {
     static final String TAG = "RecentTasksLoader";
     static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -55,11 +51,14 @@
     private Context mContext;
     private RecentsPanelView mRecentsPanel;
 
-    private AsyncTask<Void, Integer, Void> mThumbnailLoader;
+    private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader;
+    private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader;
     private final Handler mHandler;
 
     private int mIconDpi;
     private Bitmap mDefaultThumbnailBackground;
+    private Bitmap mDefaultIconBackground;
+    private int mNumTasksInFirstScreenful;
 
     public RecentTasksLoader(Context context) {
         mContext = context;
@@ -68,29 +67,28 @@
 
         // get the icon size we want -- on tablets, we use bigger icons
         boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
-        int density = res.getDisplayMetrics().densityDpi;
         if (isTablet) {
-            if (density == DisplayMetrics.DENSITY_LOW) {
-                mIconDpi = DisplayMetrics.DENSITY_MEDIUM;
-            } else if (density == DisplayMetrics.DENSITY_MEDIUM) {
-                mIconDpi = DisplayMetrics.DENSITY_HIGH;
-            } else if (density == DisplayMetrics.DENSITY_HIGH) {
-                mIconDpi = DisplayMetrics.DENSITY_XHIGH;
-            } else if (density == DisplayMetrics.DENSITY_XHIGH) {
-                // We'll need to use a denser icon, or some sort of a mipmap
-                mIconDpi = DisplayMetrics.DENSITY_XHIGH;
-            }
+            ActivityManager activityManager =
+                    (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+            mIconDpi = activityManager.getLauncherLargeIconDensity();
         } else {
             mIconDpi = res.getDisplayMetrics().densityDpi;
         }
-        mIconDpi = isTablet ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi;
+
+        // Render default icon (just a blank image)
+        int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
+        int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
+        mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
 
         // Render the default thumbnail background
-        int width = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
-        int height = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
+        int thumbnailWidth =
+                (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
+        int thumbnailHeight =
+                (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
         int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
 
-        mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        mDefaultThumbnailBackground =
+                Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
         Canvas c = new Canvas(mDefaultThumbnailBackground);
         c.drawColor(color);
 
@@ -104,12 +102,17 @@
 
     public void setRecentsPanel(RecentsPanelView recentsPanel) {
         mRecentsPanel = recentsPanel;
+        mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
     }
 
     public Bitmap getDefaultThumbnail() {
         return mDefaultThumbnailBackground;
     }
 
+    public Bitmap getDefaultIcon() {
+        return mDefaultIconBackground;
+    }
+
     // Create an TaskDescription, returning null if the title or icon is null, or if it's the
     // home activity
     TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
@@ -123,6 +126,12 @@
             homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
             .resolveActivityInfo(pm, 0);
         }
+        // Don't load the current home activity.
+        if (homeInfo != null
+            && homeInfo.packageName.equals(intent.getComponent().getPackageName())
+            && homeInfo.name.equals(intent.getComponent().getClassName())) {
+            return null;
+        }
 
         intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
                 | Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -130,9 +139,8 @@
         if (resolveInfo != null) {
             final ActivityInfo info = resolveInfo.activityInfo;
             final String title = info.loadLabel(pm).toString();
-            Drawable icon = getFullResIcon(resolveInfo, pm);
 
-            if (title != null && title.length() > 0 && icon != null) {
+            if (title != null && title.length() > 0) {
                 if (DEBUG) Log.v(TAG, "creating activity desc for id="
                         + persistentTaskId + ", label=" + title);
 
@@ -140,14 +148,6 @@
                         persistentTaskId, resolveInfo, baseIntent, info.packageName,
                         description);
                 item.setLabel(title);
-                item.setIcon(icon);
-
-                // Don't load the current home activity.
-                if (homeInfo != null
-                        && homeInfo.packageName.equals(intent.getComponent().getPackageName())
-                        && homeInfo.name.equals(intent.getComponent().getClassName())) {
-                    return null;
-                }
 
                 return item;
             } else {
@@ -157,10 +157,12 @@
         return null;
     }
 
-    void loadThumbnail(TaskDescription td) {
+    void loadThumbnailAndIcon(TaskDescription td) {
         final ActivityManager am = (ActivityManager)
                 mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        final PackageManager pm = mContext.getPackageManager();
         ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(td.persistentTaskId);
+        Drawable icon = getFullResIcon(td.resolveInfo, pm);
 
         if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
                 + td + ": " + thumbs.mainThumbnail);
@@ -170,6 +172,10 @@
             } else {
                 td.setThumbnail(mDefaultThumbnailBackground);
             }
+            if (icon != null) {
+                td.setIcon(icon);
+            }
+            td.setLoaded(true);
         }
     }
 
@@ -203,111 +209,149 @@
         return getFullResDefaultActivityIcon();
     }
 
-    public void cancelLoadingThumbnails() {
+    public void cancelLoadingThumbnailsAndIcons() {
+        if (mTaskLoader != null) {
+            mTaskLoader.cancel(false);
+            mTaskLoader = null;
+        }
         if (mThumbnailLoader != null) {
             mThumbnailLoader.cancel(false);
             mThumbnailLoader = null;
         }
     }
 
-    // return a snapshot of the current list of recent apps
-    ArrayList<TaskDescription> getRecentTasks() {
-        cancelLoadingThumbnails();
-
-        ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
-        final PackageManager pm = mContext.getPackageManager();
-        final ActivityManager am = (ActivityManager)
+    public void loadTasksInBackground() {
+        // cancel all previous loading of tasks and thumbnails
+        cancelLoadingThumbnailsAndIcons();
+        final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails =
+                new LinkedBlockingQueue<TaskDescription>();
+        final ArrayList<TaskDescription> taskDescriptionsWaitingToLoad =
+                new ArrayList<TaskDescription>();
+        mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() {
+            @Override
+            protected void onProgressUpdate(ArrayList<TaskDescription>... values) {
+                if (!isCancelled()) {
+                    ArrayList<TaskDescription> newTasks = values[0];
+                    // do a callback to RecentsPanelView to let it know we have more values
+                    // how do we let it know we're all done? just always call back twice
+                    mRecentsPanel.onTasksLoaded(newTasks);
+                }
+            }
+            @Override
+            protected Void doInBackground(Void... params) {
+                // We load in two stages: first, we update progress with just the first screenful
+                // of items. Then, we update with the rest of the items
+                final int origPri = Process.getThreadPriority(Process.myTid());
+                Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
+                final PackageManager pm = mContext.getPackageManager();
+                final ActivityManager am = (ActivityManager)
                 mContext.getSystemService(Context.ACTIVITY_SERVICE);
 
-        final List<ActivityManager.RecentTaskInfo> recentTasks =
-                am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+                final List<ActivityManager.RecentTaskInfo> recentTasks =
+                        am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
+                int numTasks = recentTasks.size();
+                ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
+                        .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
 
-        ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
-                    .resolveActivityInfo(pm, 0);
+                boolean firstScreenful = true;
+                ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
 
-        HashSet<Integer> recentTasksToKeepInCache = new HashSet<Integer>();
-        int numTasks = recentTasks.size();
-
-        // skip the first task - assume it's either the home screen or the current activity.
-        final int first = 1;
-        recentTasksToKeepInCache.add(recentTasks.get(0).persistentId);
-        for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
-            final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
-
-            TaskDescription item = createTaskDescription(recentInfo.id,
-                    recentInfo.persistentId, recentInfo.baseIntent,
-                    recentInfo.origActivity, recentInfo.description, homeInfo);
-
-            if (item != null) {
-                tasks.add(item);
-                ++index;
-            }
-        }
-
-        // when we're not using the TaskDescription cache, we load the thumbnails in the
-        // background
-        loadThumbnailsInBackground(new ArrayList<TaskDescription>(tasks));
-        return tasks;
-    }
-
-    private void loadThumbnailsInBackground(final ArrayList<TaskDescription> descriptions) {
-        if (descriptions.size() > 0) {
-            if (DEBUG) Log.v(TAG, "Showing " + descriptions.size() + " tasks");
-            loadThumbnail(descriptions.get(0));
-            if (descriptions.size() > 1) {
-                mThumbnailLoader = new AsyncTask<Void, Integer, Void>() {
-                    @Override
-                    protected void onProgressUpdate(Integer... values) {
-                        final TaskDescription td = descriptions.get(values[0]);
-                        if (!isCancelled()) {
-                            mRecentsPanel.onTaskThumbnailLoaded(td);
-                        }
-                        // This is to prevent the loader thread from getting ahead
-                        // of our UI updates.
-                        mHandler.post(new Runnable() {
-                            @Override public void run() {
-                                synchronized (td) {
-                                    td.notifyAll();
-                                }
-                            }
-                        });
+                // skip the first task - assume it's either the home screen or the current activity.
+                final int first = 1;
+                for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
+                    if (isCancelled()) {
+                        break;
                     }
+                    final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
+                    TaskDescription item = createTaskDescription(recentInfo.id,
+                            recentInfo.persistentId, recentInfo.baseIntent,
+                            recentInfo.origActivity, recentInfo.description, homeInfo);
 
-                    @Override
-                    protected Void doInBackground(Void... params) {
-                        final int origPri = Process.getThreadPriority(Process.myTid());
-                        Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
-                        long nextTime = SystemClock.uptimeMillis();
-                        for (int i=1; i<descriptions.size(); i++) {
-                            TaskDescription td = descriptions.get(i);
-                            loadThumbnail(td);
-                            long now = SystemClock.uptimeMillis();
-                            nextTime += 0;
-                            if (nextTime > now) {
-                                try {
-                                    Thread.sleep(nextTime-now);
-                                } catch (InterruptedException e) {
-                                }
-                            }
-
-                            if (isCancelled()) {
+                    if (item != null) {
+                        while (true) {
+                            try {
+                                tasksWaitingForThumbnails.put(item);
                                 break;
-                            }
-                            synchronized (td) {
-                                publishProgress(i);
-                                try {
-                                    td.wait(500);
-                                } catch (InterruptedException e) {
-                                }
+                            } catch (InterruptedException e) {
                             }
                         }
-                        Process.setThreadPriority(origPri);
-                        return null;
+                        tasks.add(item);
+                        if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) {
+                            publishProgress(tasks);
+                            tasks = new ArrayList<TaskDescription>();
+                            firstScreenful = false;
+                            //break;
+                        }
+                        ++index;
                     }
-                };
-                mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+                }
+
+                if (!isCancelled()) {
+                    publishProgress(tasks);
+                    if (firstScreenful) {
+                        // always should publish two updates
+                        publishProgress(new ArrayList<TaskDescription>());
+                    }
+                }
+
+                while (true) {
+                    try {
+                        tasksWaitingForThumbnails.put(new TaskDescription());
+                        break;
+                    } catch (InterruptedException e) {
+                    }
+                }
+
+                Process.setThreadPriority(origPri);
+                return null;
             }
-        }
+        };
+        mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails);
     }
 
+    private void loadThumbnailsAndIconsInBackground(
+            final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) {
+        // continually read items from tasksWaitingForThumbnails and load
+        // thumbnails and icons for them. finish thread when cancelled or there
+        // is a null item in tasksWaitingForThumbnails
+        mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() {
+            @Override
+            protected void onProgressUpdate(TaskDescription... values) {
+                if (!isCancelled()) {
+                    TaskDescription td = values[0];
+                    mRecentsPanel.onTaskThumbnailLoaded(td);
+                }
+            }
+            @Override
+            protected Void doInBackground(Void... params) {
+                final int origPri = Process.getThreadPriority(Process.myTid());
+                Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE);
+
+                while (true) {
+                    if (isCancelled()) {
+                        break;
+                    }
+                    TaskDescription td = null;
+                    while (td == null) {
+                        try {
+                            td = tasksWaitingForThumbnails.take();
+                        } catch (InterruptedException e) {
+                        }
+                    }
+                    if (td.isNull()) {
+                        break;
+                    }
+                    loadThumbnailAndIcon(td);
+                    synchronized(td) {
+                        publishProgress(td);
+                    }
+                }
+
+                Process.setThreadPriority(origPri);
+                return null;
+            }
+        };
+        mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index f971d2d..4718a17 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -22,11 +22,18 @@
 import android.database.DataSetObserver;
 import android.graphics.Canvas;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.FloatMath;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
+import android.view.View.MeasureSpec;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
 import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.widget.HorizontalScrollView;
 import android.widget.LinearLayout;
 
@@ -34,6 +41,8 @@
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
 
+import java.util.ArrayList;
+
 public class RecentsHorizontalScrollView extends HorizontalScrollView
     implements SwipeHelper.Callback {
     private static final String TAG = RecentsPanelView.TAG;
@@ -44,6 +53,8 @@
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
     private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+    private ArrayList<View> mRecycledViews;
+    private int mNumItemsInOneScreenful;
 
     public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
@@ -51,6 +62,7 @@
         float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
         mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop);
         mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false);
+        mRecycledViews = new ArrayList<View>();
     }
 
     private int scrollPositionOfMostRecent() {
@@ -58,9 +70,23 @@
     }
 
     private void update() {
+        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+            View v = mLinearLayout.getChildAt(i);
+            mRecycledViews.add(v);
+            mAdapter.recycleView(v);
+        }
+        LayoutTransition transitioner = getLayoutTransition();
+        setLayoutTransition(null);
+
         mLinearLayout.removeAllViews();
         for (int i = 0; i < mAdapter.getCount(); i++) {
-            final View view = mAdapter.getView(i, null, mLinearLayout);
+            View old = null;
+            if (mRecycledViews.size() != 0) {
+                old = mRecycledViews.remove(mRecycledViews.size() - 1);
+                old.setVisibility(VISIBLE);
+            }
+
+            final View view = mAdapter.getView(i, old, mLinearLayout);
 
             if (mPerformanceHelper != null) {
                 mPerformanceHelper.addViewCallback(view);
@@ -87,7 +113,8 @@
                 }
             };
 
-            final View thumbnailView = view.findViewById(R.id.app_thumbnail);
+            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
+            final View thumbnailView = holder.thumbnailView;
             OnLongClickListener longClickListener = new OnLongClickListener() {
                 public boolean onLongClick(View v) {
                     final View anchorView = view.findViewById(R.id.app_description);
@@ -107,13 +134,21 @@
             appTitle.setOnTouchListener(noOpListener);
             mLinearLayout.addView(view);
         }
+        setLayoutTransition(transitioner);
+
         // Scroll to end after layout.
-        post(new Runnable() {
-            public void run() {
-                mLastScrollPosition = scrollPositionOfMostRecent();
-                scrollTo(mLastScrollPosition, 0);
-            }
-        });
+        final ViewTreeObserver observer = getViewTreeObserver();
+
+        final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
+                public void onGlobalLayout() {
+                    mLastScrollPosition = scrollPositionOfMostRecent();
+                    scrollTo(mLastScrollPosition, 0);
+                    if (observer.isAlive()) {
+                        observer.removeOnGlobalLayoutListener(this);
+                    }
+                }
+            };
+        observer.addOnGlobalLayoutListener(updateScroll);
     }
 
     @Override
@@ -142,8 +177,10 @@
     }
 
     public void onChildDismissed(View v) {
+        mRecycledViews.add(v);
         mLinearLayout.removeView(v);
         mCallback.handleSwipe(v);
+        v.setActivated(false);
     }
 
     public void onBeginDrag(View v) {
@@ -315,6 +352,24 @@
                 update();
             }
         });
+        DisplayMetrics dm = getResources().getDisplayMetrics();
+        int childWidthMeasureSpec =
+                MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
+        int childheightMeasureSpec =
+                MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
+        View child = mAdapter.createView(mLinearLayout);
+        child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+        mNumItemsInOneScreenful =
+                (int) FloatMath.ceil(dm.widthPixels / (float) child.getMeasuredWidth());
+        mRecycledViews.add(child);
+
+        for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
+            mRecycledViews.add(mAdapter.createView(mLinearLayout));
+        }
+    }
+
+    public int numItemsInOneScreenful() {
+        return mNumItemsInOneScreenful;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index a10e363..8706f10 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -27,6 +27,7 @@
 import android.graphics.Matrix;
 import android.graphics.Shader.TileMode;
 import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.Settings;
 import android.util.AttributeSet;
@@ -36,18 +37,18 @@
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
+import android.view.ViewRootImpl;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
 import android.widget.PopupMenu;
-import android.widget.RelativeLayout;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
@@ -59,7 +60,7 @@
 
 import java.util.ArrayList;
 
-public class RecentsPanelView extends RelativeLayout implements OnItemClickListener, RecentsCallback,
+public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
         StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener {
     static final String TAG = "RecentsPanelView";
     static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -71,6 +72,10 @@
     private StatusBarTouchProxy mStatusBarTouchProxy;
 
     private boolean mShowing;
+    private boolean mWaitingToShow;
+    private boolean mWaitingToShowAnimated;
+    private boolean mReadyToShow;
+    private int mNumItemsWaitingForThumbnailsAndIcons;
     private Choreographer mChoreo;
     OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener;
 
@@ -104,6 +109,7 @@
         TextView labelView;
         TextView descriptionView;
         TaskDescription taskDescription;
+        boolean loadedThumbnailAndIcon;
     }
 
     /* package */ final class TaskDescriptionAdapter extends BaseAdapter {
@@ -125,42 +131,82 @@
             return position; // we just need something unique for this position
         }
 
-        public View getView(int position, View convertView, ViewGroup parent) {
-            ViewHolder holder;
-            if (convertView == null) {
-                convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false);
-                holder = new ViewHolder();
-                holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
-                holder.thumbnailViewImage = (ImageView) convertView.findViewById(
-                        R.id.app_thumbnail_image);
-                // If we set the default thumbnail now, we avoid an onLayout when we update
-                // the thumbnail later (if they both have the same dimensions)
+        public View createView(ViewGroup parent) {
+            View convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false);
+            ViewHolder holder = new ViewHolder();
+            holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
+            holder.thumbnailViewImage =
+                    (ImageView) convertView.findViewById(R.id.app_thumbnail_image);
+            // If we set the default thumbnail now, we avoid an onLayout when we update
+            // the thumbnail later (if they both have the same dimensions)
+            if (mRecentTasksLoader != null) {
                 updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
-
-                holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
-                holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
-                holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
-
-                convertView.setTag(holder);
-            } else {
-                holder = (ViewHolder) convertView.getTag();
             }
+            holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
+            if (mRecentTasksLoader != null) {
+                holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+            }
+            holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
+            holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
+
+            convertView.setTag(holder);
+            return convertView;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = createView(parent);
+            }
+            ViewHolder holder = (ViewHolder) convertView.getTag();
 
             // index is reverse since most recent appears at the bottom...
             final int index = mRecentTaskDescriptions.size() - position - 1;
 
             final TaskDescription td = mRecentTaskDescriptions.get(index);
-            holder.iconView.setImageDrawable(td.getIcon());
+
             holder.labelView.setText(td.getLabel());
             holder.thumbnailView.setContentDescription(td.getLabel());
-            updateThumbnail(holder, td.getThumbnail(), true, false);
+            holder.loadedThumbnailAndIcon = td.isLoaded();
+            if (td.isLoaded()) {
+                updateThumbnail(holder, td.getThumbnail(), true, false);
+                updateIcon(holder, td.getIcon(), true, false);
+                mNumItemsWaitingForThumbnailsAndIcons--;
+            }
 
             holder.thumbnailView.setTag(td);
             holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
             holder.taskDescription = td;
-
             return convertView;
         }
+
+        public void recycleView(View v) {
+            ViewHolder holder = (ViewHolder) v.getTag();
+            updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
+            holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
+            holder.iconView.setVisibility(INVISIBLE);
+            holder.labelView.setText(null);
+            holder.thumbnailView.setContentDescription(null);
+            holder.thumbnailView.setTag(null);
+            holder.thumbnailView.setOnLongClickListener(null);
+            holder.thumbnailView.setVisibility(INVISIBLE);
+            holder.taskDescription = null;
+            holder.loadedThumbnailAndIcon = false;
+        }
+    }
+
+    public int numItemsInOneScreenful() {
+        if (mRecentsContainer instanceof RecentsHorizontalScrollView){
+            RecentsHorizontalScrollView scrollView
+                    = (RecentsHorizontalScrollView) mRecentsContainer;
+            return scrollView.numItemsInOneScreenful();
+        } else if (mRecentsContainer instanceof RecentsVerticalScrollView){
+            RecentsVerticalScrollView scrollView
+                    = (RecentsVerticalScrollView) mRecentsContainer;
+            return scrollView.numItemsInOneScreenful();
+        }
+        else {
+            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
+        }
     }
 
     @Override
@@ -192,15 +238,31 @@
     }
 
     public void show(boolean show, boolean animate) {
-        show(show, animate, null);
+        if (show) {
+            mWaitingToShow = true;
+            mWaitingToShowAnimated = animate;
+            showIfReady();
+        } else {
+            show(show, animate, null, false);
+        }
+    }
+
+    private void showIfReady() {
+        // mWaitingToShow = there was a touch up on the recents button
+        // mReadyToShow = we've created views for the first screenful of items
+        if (mWaitingToShow && mReadyToShow) { // && mNumItemsWaitingForThumbnailsAndIcons <= 0
+            show(true, mWaitingToShowAnimated, null, false);
+        }
     }
 
     public void show(boolean show, boolean animate,
-            ArrayList<TaskDescription> recentTaskDescriptions) {
+            ArrayList<TaskDescription> recentTaskDescriptions, boolean firstScreenful) {
+        // For now, disable animations. We may want to re-enable in the future
+        animate = false;
         if (show) {
             // Need to update list of recent apps before we set visibility so this view's
             // content description is updated before it gets focus for TalkBack mode
-            refreshRecentTasksList(recentTaskDescriptions);
+            refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
 
             // if there are no apps, either bring up a "No recent apps" message, or just
             // quit early
@@ -209,19 +271,24 @@
                 mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
             } else {
                 if (noApps) {
-                    if (DEBUG) Log.v(TAG, "Nothing to show");
+                   if (DEBUG) Log.v(TAG, "Nothing to show");
                     // Need to set recent tasks to dirty so that next time we load, we
                     // refresh the list of tasks
-                    mRecentTasksLoader.cancelLoadingThumbnails();
+                    mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
                     mRecentTasksDirty = true;
+
+                    mWaitingToShow = false;
+                    mReadyToShow = false;
                     return;
                 }
             }
         } else {
             // Need to set recent tasks to dirty so that next time we load, we
             // refresh the list of tasks
-            mRecentTasksLoader.cancelLoadingThumbnails();
+            mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
             mRecentTasksDirty = true;
+            mWaitingToShow = false;
+            mReadyToShow = false;
         }
         if (animate) {
             if (mShowing != show) {
@@ -385,7 +452,6 @@
             throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
         }
 
-
         mRecentsScrim = findViewById(R.id.recents_bg_protect);
         mRecentsNoApps = findViewById(R.id.recents_no_apps);
         mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
@@ -425,6 +491,20 @@
         }
     }
 
+
+    private void updateIcon(ViewHolder h, Drawable icon, boolean show, boolean anim) {
+        if (icon != null) {
+            h.iconView.setImageDrawable(icon);
+            if (show && h.iconView.getVisibility() != View.VISIBLE) {
+                if (anim) {
+                    h.iconView.setAnimation(
+                            AnimationUtils.loadAnimation(mContext, R.anim.recent_appear));
+                }
+                h.iconView.setVisibility(View.VISIBLE);
+            }
+        }
+    }
+
     private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) {
         if (thumbnail != null) {
             // Should remove the default image in the frame
@@ -458,31 +538,36 @@
         }
     }
 
-    void onTaskThumbnailLoaded(TaskDescription ad) {
-        synchronized (ad) {
+    void onTaskThumbnailLoaded(TaskDescription td) {
+        synchronized (td) {
             if (mRecentsContainer != null) {
                 ViewGroup container = mRecentsContainer;
                 if (container instanceof HorizontalScrollView
                         || container instanceof ScrollView) {
-                    container = (ViewGroup)container.findViewById(
+                    container = (ViewGroup) container.findViewById(
                             R.id.recents_linear_layout);
                 }
                 // Look for a view showing this thumbnail, to update.
-                for (int i=0; i<container.getChildCount(); i++) {
+                for (int i=0; i < container.getChildCount(); i++) {
                     View v = container.getChildAt(i);
                     if (v.getTag() instanceof ViewHolder) {
                         ViewHolder h = (ViewHolder)v.getTag();
-                        if (h.taskDescription == ad) {
+                        if (!h.loadedThumbnailAndIcon && h.taskDescription == td) {
                             // only fade in the thumbnail if recents is already visible-- we
                             // show it immediately otherwise
-                            boolean animateShow = mShowing &&
-                                mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
-                            updateThumbnail(h, ad.getThumbnail(), true, animateShow);
+                            //boolean animateShow = mShowing &&
+                            //    mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
+                            boolean animateShow = false;
+                            updateIcon(h, td.getIcon(), true, animateShow);
+                            updateThumbnail(h, td.getThumbnail(), true, animateShow);
+                            h.loadedThumbnailAndIcon = true;
+                            mNumItemsWaitingForThumbnailsAndIcons--;
                         }
                     }
                 }
             }
-        }
+            }
+        showIfReady();
     }
 
     // additional optimization when we have sofware system buttons - start loading the recent
@@ -516,7 +601,7 @@
     public void clearRecentTasksList() {
         // Clear memory used by screenshots
         if (mRecentTaskDescriptions != null) {
-            mRecentTasksLoader.cancelLoadingThumbnails();
+            mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
             mRecentTaskDescriptions.clear();
             mListAdapter.notifyDataSetInvalidated();
             mRecentTasksDirty = true;
@@ -524,26 +609,50 @@
     }
 
     public void refreshRecentTasksList() {
-        refreshRecentTasksList(null);
+        refreshRecentTasksList(null, false);
     }
 
-    private void refreshRecentTasksList(ArrayList<TaskDescription> recentTasksList) {
+    private void refreshRecentTasksList(
+            ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
         if (mRecentTasksDirty) {
             if (recentTasksList != null) {
-                mRecentTaskDescriptions = recentTasksList;
+                mFirstScreenful = true;
+                onTasksLoaded(recentTasksList);
             } else {
-                mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks();
+                mFirstScreenful = true;
+                mRecentTasksLoader.loadTasksInBackground();
             }
-            mListAdapter.notifyDataSetInvalidated();
-            updateUiElements(getResources().getConfiguration());
             mRecentTasksDirty = false;
         }
     }
 
+    boolean mFirstScreenful;
+    public void onTasksLoaded(ArrayList<TaskDescription> tasks) {
+        if (!mFirstScreenful && tasks.size() == 0) {
+            return;
+        }
+        mNumItemsWaitingForThumbnailsAndIcons =
+                mFirstScreenful ? tasks.size() : mRecentTaskDescriptions.size();
+        if (mRecentTaskDescriptions == null) {
+            mRecentTaskDescriptions = new ArrayList(tasks);
+        } else {
+            mRecentTaskDescriptions.addAll(tasks);
+        }
+        mListAdapter.notifyDataSetInvalidated();
+        updateUiElements(getResources().getConfiguration());
+        mReadyToShow = true;
+        mFirstScreenful = false;
+        showIfReady();
+    }
+
     public ArrayList<TaskDescription> getRecentTasksList() {
         return mRecentTaskDescriptions;
     }
 
+    public boolean getFirstScreenful() {
+        return mFirstScreenful;
+    }
+
     private void updateUiElements(Configuration config) {
         final int items = mRecentTaskDescriptions.size();
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index dc13092..0605c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -22,10 +22,18 @@
 import android.database.DataSetObserver;
 import android.graphics.Canvas;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.FloatMath;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.view.View.OnTouchListener;
 import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 
@@ -33,6 +41,8 @@
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
 
+import java.util.ArrayList;
+
 public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper.Callback {
     private static final String TAG = RecentsPanelView.TAG;
     private static final boolean DEBUG = RecentsPanelView.DEBUG;
@@ -42,6 +52,8 @@
     protected int mLastScrollPosition;
     private SwipeHelper mSwipeHelper;
     private RecentsScrollViewPerformanceHelper mPerformanceHelper;
+    private ArrayList<View> mRecycledViews;
+    private int mNumItemsInOneScreenful;
 
     public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
@@ -50,6 +62,7 @@
         mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
 
         mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true);
+        mRecycledViews = new ArrayList<View>();
     }
 
     private int scrollPositionOfMostRecent() {
@@ -57,77 +70,91 @@
     }
 
     private void update() {
+        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+            View v = mLinearLayout.getChildAt(i);
+            mRecycledViews.add(v);
+            mAdapter.recycleView(v);
+        }
+        LayoutTransition transitioner = getLayoutTransition();
+        setLayoutTransition(null);
+
         mLinearLayout.removeAllViews();
         // Once we can clear the data associated with individual item views,
         // we can get rid of the removeAllViews() and the code below will
         // recycle them.
         for (int i = 0; i < mAdapter.getCount(); i++) {
             View old = null;
-            if (i < mLinearLayout.getChildCount()) {
-                old = mLinearLayout.getChildAt(i);
-                old.setVisibility(View.VISIBLE);
+            if (mRecycledViews.size() != 0) {
+                old = mRecycledViews.remove(mRecycledViews.size() - 1);
+                old.setVisibility(VISIBLE);
             }
+
             final View view = mAdapter.getView(i, old, mLinearLayout);
 
             if (mPerformanceHelper != null) {
                 mPerformanceHelper.addViewCallback(view);
             }
 
-            if (old == null) {
-                OnTouchListener noOpListener = new OnTouchListener() {
-                    @Override
-                    public boolean onTouch(View v, MotionEvent event) {
-                        return true;
-                    }
-                };
+            OnTouchListener noOpListener = new OnTouchListener() {
+                @Override
+                public boolean onTouch(View v, MotionEvent event) {
+                    return true;
+                }
+            };
 
-                view.setOnClickListener(new OnClickListener() {
-                    public void onClick(View v) {
-                        mCallback.dismiss();
-                    }
-                });
-                // We don't want a click sound when we dimiss recents
-                view.setSoundEffectsEnabled(false);
+            view.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    mCallback.dismiss();
+                }
+            });
+            // We don't want a click sound when we dimiss recents
+            view.setSoundEffectsEnabled(false);
 
-                OnClickListener launchAppListener = new OnClickListener() {
-                    public void onClick(View v) {
-                        mCallback.handleOnClick(view);
-                    }
-                };
+            OnClickListener launchAppListener = new OnClickListener() {
+                public void onClick(View v) {
+                    mCallback.handleOnClick(view);
+                }
+            };
 
-                final View thumbnailView = view.findViewById(R.id.app_thumbnail);
-                OnLongClickListener longClickListener = new OnLongClickListener() {
-                    public boolean onLongClick(View v) {
-                        final View anchorView = view.findViewById(R.id.app_description);
-                        mCallback.handleLongPress(view, anchorView, thumbnailView);
-                        return true;
-                    }
-                };
-                thumbnailView.setClickable(true);
-                thumbnailView.setOnClickListener(launchAppListener);
-                thumbnailView.setOnLongClickListener(longClickListener);
+            RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
+            final View thumbnailView = holder.thumbnailView;
+            OnLongClickListener longClickListener = new OnLongClickListener() {
+                public boolean onLongClick(View v) {
+                    final View anchorView = view.findViewById(R.id.app_description);
+                    mCallback.handleLongPress(view, anchorView, thumbnailView);
+                    return true;
+                }
+            };
+            thumbnailView.setClickable(true);
+            thumbnailView.setOnClickListener(launchAppListener);
+            thumbnailView.setOnLongClickListener(longClickListener);
 
-                // We don't want to dismiss recents if a user clicks on the app title
-                // (we also don't want to launch the app either, though, because the
-                // app title is a small target and doesn't have great click feedback)
-                final View appTitle = view.findViewById(R.id.app_label);
-                appTitle.setContentDescription(" ");
-                appTitle.setOnTouchListener(noOpListener);
-                final View calloutLine = view.findViewById(R.id.recents_callout_line);
-                calloutLine.setOnTouchListener(noOpListener);
-                mLinearLayout.addView(view);
-            }
+            // We don't want to dismiss recents if a user clicks on the app title
+            // (we also don't want to launch the app either, though, because the
+            // app title is a small target and doesn't have great click feedback)
+            final View appTitle = view.findViewById(R.id.app_label);
+            appTitle.setContentDescription(" ");
+            appTitle.setOnTouchListener(noOpListener);
+            final View calloutLine = view.findViewById(R.id.recents_callout_line);
+            calloutLine.setOnTouchListener(noOpListener);
+
+            mLinearLayout.addView(view);
         }
-        for (int i = mAdapter.getCount(); i < mLinearLayout.getChildCount(); i++) {
-            mLinearLayout.getChildAt(i).setVisibility(View.GONE);
-        }
+        setLayoutTransition(transitioner);
+
         // Scroll to end after layout.
-        post(new Runnable() {
-            public void run() {
-                mLastScrollPosition = scrollPositionOfMostRecent();
-                scrollTo(0, mLastScrollPosition);
-            }
-        });
+        final ViewTreeObserver observer = getViewTreeObserver();
+
+        final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
+                public void onGlobalLayout() {
+                    mLastScrollPosition = scrollPositionOfMostRecent();
+                    scrollTo(0, mLastScrollPosition);
+                    if (observer.isAlive()) {
+                        observer.removeOnGlobalLayoutListener(this);
+                    }
+                }
+            };
+        observer.addOnGlobalLayoutListener(updateScroll);
     }
 
     @Override
@@ -156,8 +183,10 @@
     }
 
     public void onChildDismissed(View v) {
+        mRecycledViews.add(v);
         mLinearLayout.removeView(v);
         mCallback.handleSwipe(v);
+        v.setActivated(false);
     }
 
     public void onBeginDrag(View v) {
@@ -330,6 +359,25 @@
                 update();
             }
         });
+
+        DisplayMetrics dm = getResources().getDisplayMetrics();
+        int childWidthMeasureSpec =
+                MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
+        int childheightMeasureSpec =
+                MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
+        View child = mAdapter.createView(mLinearLayout);
+        child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+        mNumItemsInOneScreenful =
+                (int) FloatMath.ceil(dm.heightPixels / (float) child.getMeasuredHeight());
+        mRecycledViews.add(child);
+
+        for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
+            mRecycledViews.add(mAdapter.createView(mLinearLayout));
+        }
+    }
+
+    public int numItemsInOneScreenful() {
+        return mNumItemsInOneScreenful;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
index dcfd6d8..7e979b7 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java
@@ -32,6 +32,7 @@
     private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail()
     private Drawable mIcon; // application package icon
     private CharSequence mLabel; // application package label
+    private boolean mLoaded;
 
     public TaskDescription(int _taskId, int _persistentTaskId,
             ResolveInfo _resolveInfo, Intent _intent,
@@ -45,6 +46,28 @@
         packageName = _packageName;
     }
 
+    public TaskDescription() {
+        resolveInfo = null;
+        intent = null;
+        taskId = -1;
+        persistentTaskId = -1;
+
+        description = null;
+        packageName = null;
+    }
+
+    public void setLoaded(boolean loaded) {
+        mLoaded = loaded;
+    }
+
+    public boolean isLoaded() {
+        return mLoaded;
+    }
+
+    public boolean isNull() {
+        return resolveInfo == null;
+    }
+
     // mark all these as locked?
     public CharSequence getLabel() {
         return mLabel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 69a247d..d33ed3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -23,6 +23,8 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
 import android.os.ServiceManager;
 import android.util.AttributeSet;
 import android.util.Slog;
@@ -66,6 +68,35 @@
     int mDisabledFlags = 0;
     int mNavigationIconHints = 0;
 
+    // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
+    final static boolean WORKAROUND_INVALID_LAYOUT = true;
+    final static int MSG_CHECK_INVALID_LAYOUT = 8686;
+
+    private class H extends Handler {
+        public void handleMessage(Message m) {
+            switch (m.what) {
+                case MSG_CHECK_INVALID_LAYOUT:
+                    final String how = "" + m.obj;
+                    final int w = getWidth();
+                    final int h = getHeight();
+                    final int vw = mCurrentView.getWidth();
+                    final int vh = mCurrentView.getHeight();
+
+                    if (h != vh || w != vw) {
+                        Slog.w(TAG, String.format(
+                            "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)",
+                            how, w, h, vw, vh));
+                        if (WORKAROUND_INVALID_LAYOUT) {
+                            requestLayout();
+                        }
+                    }
+                    break;
+            }
+        }
+    }
+
+    private H mHandler = new H();
+
     public View getRecentsButton() {
         return mCurrentView.findViewById(R.id.recent_apps);
     }
@@ -275,6 +306,36 @@
         }
     }
 
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        if (DEBUG) Slog.d(TAG, String.format(
+                    "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
+        postCheckForInvalidLayout("sizeChanged");
+        super.onSizeChanged(w, h, oldw, oldh);
+    }
+
+    /*
+    @Override
+    protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
+        if (DEBUG) Slog.d(TAG, String.format(
+                    "onLayout: %s (%d,%d,%d,%d)", 
+                    changed?"changed":"notchanged", left, top, right, bottom));
+        super.onLayout(changed, left, top, right, bottom);
+    }
+
+    // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else
+    // fails, any touch on the display will fix the layout.
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (DEBUG) Slog.d(TAG, "onInterceptTouchEvent: " + ev.toString());
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            postCheckForInvalidLayout("touch");
+        }
+        return super.onInterceptTouchEvent(ev);
+    }
+    */
+        
+
     private String getResourceName(int resId) {
         if (resId != 0) {
             final android.content.res.Resources res = mContext.getResources();
@@ -288,6 +349,10 @@
         }
     }
 
+    private void postCheckForInvalidLayout(final String how) {
+        mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget();
+    }
+
     private static String visibilityToString(int vis) {
         switch (vis) {
             case View.INVISIBLE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5a1e3f4..b3cef90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -393,7 +393,7 @@
         }
         lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
         lp.setTitle("RecentsPanel");
-        lp.windowAnimations = R.style.Animation_RecentPanel;
+        lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications;
         lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
         | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
         return lp;
@@ -403,11 +403,13 @@
         // Recents Panel
         boolean visible = false;
         ArrayList<TaskDescription> recentTasksList = null;
+        boolean firstScreenful = false;
         if (mRecentsPanel != null) {
             visible = mRecentsPanel.isShowing();
             WindowManagerImpl.getDefault().removeView(mRecentsPanel);
             if (visible) {
                 recentTasksList = mRecentsPanel.getRecentTasksList();
+                firstScreenful = mRecentsPanel.getFirstScreenful();
             }
         }
 
@@ -425,7 +427,7 @@
         WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
         mRecentsPanel.setBar(this);
         if (visible) {
-            mRecentsPanel.show(true, false, recentTasksList);
+            mRecentsPanel.show(true, false, recentTasksList, firstScreenful);
         }
 
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index d09e680..c59290c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -88,6 +88,7 @@
     int mLastSignalLevel;
     boolean mShowPhoneRSSIForData = false;
     boolean mShowAtLeastThreeGees = false;
+    boolean mAlwaysShowCdmaRssi = false;
 
     String mContentDescriptionPhoneSignal;
     String mContentDescriptionWifi;
@@ -156,7 +157,7 @@
     IBatteryStats mBatteryStats;
 
     public interface SignalCluster {
-        void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon, 
+        void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon,
                 String contentDescription);
         void setMobileDataIndicators(boolean visible, int strengthIcon, int activityIcon,
                 int typeIcon, String contentDescription, String typeContentDescription);
@@ -176,6 +177,8 @@
 
         mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData);
         mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G);
+        mAlwaysShowCdmaRssi = res.getBoolean(
+                com.android.internal.R.bool.config_alwaysUseCdmaRssi);
 
         // set up the default wifi icon, used when no radios have ever appeared
         updateWifiIcons();
@@ -287,7 +290,7 @@
             // wimax is special
             cluster.setMobileDataIndicators(
                     true,
-                    mWimaxIconId,
+                    mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId,
                     mMobileActivityIconId,
                     mDataTypeIconId,
                     mContentDescriptionWimax,
@@ -351,7 +354,7 @@
         @Override
         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
             if (DEBUG) {
-                Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength + 
+                Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
                     ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
             }
             mSignalStrength = signalStrength;
@@ -469,7 +472,15 @@
             } else {
                 int iconLevel;
                 int[] iconList;
-                mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
+                if (isCdma() && mAlwaysShowCdmaRssi) {
+                    mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel();
+                    if(DEBUG) Slog.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi
+                            + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel()
+                            + " instead of level=" + mSignalStrength.getLevel());
+                } else {
+                    mLastSignalLevel = iconLevel = mSignalStrength.getLevel();
+                }
+
                 if (isCdma()) {
                     if (isCdmaEri()) {
                         iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition];
@@ -487,7 +498,6 @@
                 mPhoneSignalIconId = iconList[iconLevel];
                 mContentDescriptionPhoneSignal = mContext.getString(
                         AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]);
-
                 mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel];
             }
         }
@@ -588,8 +598,12 @@
             }
         }
 
-        if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
-            mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+        if (isCdma()) {
+            if (isCdmaEri()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+            }
+        } else if (mPhone.isNetworkRoaming()) {
+                mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
         }
     }
 
@@ -850,8 +864,10 @@
             Slog.d(TAG, "updateConnectivity: intent=" + intent);
         }
 
-        NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
-                ConnectivityManager.EXTRA_NETWORK_INFO));
+        final ConnectivityManager connManager = (ConnectivityManager) mContext
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+        final NetworkInfo info = connManager.getActiveNetworkInfo();
+
         int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
 
         if (CHATTY) {
@@ -890,34 +906,51 @@
 
         if (!mHasMobileDataFeature) {
             mDataSignalIconId = mPhoneSignalIconId = 0;
-        } else if (mDataConnected) {
-            mobileLabel = mNetworkName;
-            if (DEBUG) {
-                mobileLabel += "yyyyYYYYyyyyYYYY";
-            }
-            combinedSignalIconId = mDataSignalIconId;
-            switch (mDataActivity) {
-                case TelephonyManager.DATA_ACTIVITY_IN:
-                    mMobileActivityIconId = R.drawable.stat_sys_signal_in;
-                    break;
-                case TelephonyManager.DATA_ACTIVITY_OUT:
-                    mMobileActivityIconId = R.drawable.stat_sys_signal_out;
-                    break;
-                case TelephonyManager.DATA_ACTIVITY_INOUT:
-                    mMobileActivityIconId = R.drawable.stat_sys_signal_inout;
-                    break;
-                default:
-                    mMobileActivityIconId = 0;
-                    break;
+            mobileLabel = "";
+        } else {
+            // We want to show the carrier name if in service and either:
+            //   - We are connected to mobile data, or
+            //   - We are not connected to mobile data, as long as the *reason* packets are not
+            //     being routed over that link is that we have better connectivity via wifi.
+            // If data is disconnected for some other reason but wifi is connected, we show nothing.
+            // Otherwise (nothing connected) we show "No internet connection".
+
+            if (mDataConnected) {
+                mobileLabel = mNetworkName;
+            } else if (mWifiConnected) {
+                if (hasService()) {
+                    mobileLabel = mNetworkName;
+                } else {
+                    mobileLabel = "";
+                }
+            } else {
+                mobileLabel
+                    = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
             }
 
-            combinedLabel = mobileLabel;
-            combinedActivityIconId = mMobileActivityIconId;
-            combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
-            mContentDescriptionCombinedSignal = mContentDescriptionDataType;
-        } else {
-            mobileLabel = mHasMobileDataFeature ?
-                context.getString(R.string.status_bar_settings_signal_meter_disconnected) : "";
+            // Now for things that should only be shown when actually using mobile data.
+            if (mDataConnected) {
+                combinedSignalIconId = mDataSignalIconId;
+                switch (mDataActivity) {
+                    case TelephonyManager.DATA_ACTIVITY_IN:
+                        mMobileActivityIconId = R.drawable.stat_sys_signal_in;
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_OUT:
+                        mMobileActivityIconId = R.drawable.stat_sys_signal_out;
+                        break;
+                    case TelephonyManager.DATA_ACTIVITY_INOUT:
+                        mMobileActivityIconId = R.drawable.stat_sys_signal_inout;
+                        break;
+                    default:
+                        mMobileActivityIconId = 0;
+                        break;
+                }
+
+                combinedLabel = mobileLabel;
+                combinedActivityIconId = mMobileActivityIconId;
+                combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
+                mContentDescriptionCombinedSignal = mContentDescriptionDataType;
+            }
         }
 
         if (mWifiConnected) {
@@ -949,6 +982,12 @@
             combinedLabel = wifiLabel;
             combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
             mContentDescriptionCombinedSignal = mContentDescriptionWifi;
+        } else {
+            if (mHasMobileDataFeature) {
+                wifiLabel = "";
+            } else {
+                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+            }
         }
 
         if (mBluetoothTethered) {
@@ -969,9 +1008,17 @@
             mDataTypeIconId = 0;
 
             // combined values from connected wifi take precedence over airplane mode
-            if (!mWifiConnected) {
-                wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
-                combinedLabel = wifiLabel;
+            if (mWifiConnected) {
+                // Suppress "No internet connection." from mobile if wifi connected.
+                mobileLabel = "";
+            } else {
+                if (mHasMobileDataFeature) {
+                    // let the mobile icon show "No internet connection."
+                    wifiLabel = "";
+                } else {
+                    wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+                    combinedLabel = wifiLabel;
+                }
                 mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
                 combinedSignalIconId = mDataSignalIconId;
             }
@@ -986,10 +1033,13 @@
             mContentDescriptionCombinedSignal = mHasMobileDataFeature
                 ? mContentDescriptionDataType : mContentDescriptionWifi;
 
-            if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
+            mDataTypeIconId = 0;
+            if (isCdma()) {
+                if (isCdmaEri()) {
+                    mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+                }
+            } else if (mPhone.isNetworkRoaming()) {
                 mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
-            } else {
-                mDataTypeIconId = 0;
             }
         }
 
@@ -1150,7 +1200,7 @@
                 v.setText(wifiLabel);
             }
         }
-        
+
         // mobile label
         N = mMobileLabelViews.size();
         for (int i=0; i<N; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 6287408..5151cad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -456,8 +456,7 @@
             // Sanity-check that someone hasn't set up the config wrong and asked for a navigation
             // bar on a tablet that has only the system bar
             if (mWindowManager.hasNavigationBar()) {
-                throw new RuntimeException(
-                        "Tablet device cannot show navigation bar and system bar");
+                Slog.e(TAG, "Tablet device cannot show navigation bar and system bar");
             }
         } catch (RemoteException ex) {
         }
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 8e062b7..46c0f83 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -5,7 +5,7 @@
     <application android:label="VpnDialogs"
             android:allowBackup="false" >
         <activity android:name=".ConfirmDialog"
-                android:theme="@style/transparent">
+                android:theme="@*android:style/Theme.Holo.Dialog.Alert">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.DEFAULT"/>
@@ -13,7 +13,7 @@
         </activity>
 
         <activity android:name=".ManageDialog"
-                android:theme="@style/transparent"
+                android:theme="@*android:style/Theme.Holo.Dialog.Alert"
                 android:noHistory="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/packages/VpnDialogs/res/values/styles.xml b/packages/VpnDialogs/res/values/styles.xml
index cf10596..e3469ec 100644
--- a/packages/VpnDialogs/res/values/styles.xml
+++ b/packages/VpnDialogs/res/values/styles.xml
@@ -15,13 +15,6 @@
 -->
 
 <resources>
-
-    <style name="transparent">
-        <item name="android:windowBackground">@android:color/transparent</item>
-        <item name="android:windowNoTitle">true</item>
-        <item name="android:windowIsFloating">true</item>
-    </style>
-
     <style name="label">
         <item name="android:gravity">center_vertical|right</item>
         <item name="android:paddingRight">2mm</item>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index c7b4a5f..13d8019 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -16,8 +16,6 @@
 
 package com.android.vpndialogs;
 
-import android.app.Activity;
-import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -32,15 +30,16 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-public class ConfirmDialog extends Activity implements CompoundButton.OnCheckedChangeListener,
-        DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+import com.android.internal.app.AlertActivity;
+
+public class ConfirmDialog extends AlertActivity implements
+        CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener {
     private static final String TAG = "VpnConfirm";
 
     private String mPackage;
 
     private IConnectivityManager mService;
 
-    private AlertDialog mDialog;
     private Button mButton;
 
     @Override
@@ -67,18 +66,17 @@
                     getString(R.string.prompt, app.loadLabel(pm)));
             ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this);
 
-            mDialog = new AlertDialog.Builder(this)
-                    .setIcon(android.R.drawable.ic_dialog_alert)
-                    .setTitle(android.R.string.dialog_alert_title)
-                    .setView(view)
-                    .setPositiveButton(android.R.string.ok, this)
-                    .setNegativeButton(android.R.string.cancel, this)
-                    .setCancelable(false)
-                    .create();
-            mDialog.setOnDismissListener(this);
-            mDialog.show();
+            mAlertParams.mIconId = android.R.drawable.ic_dialog_alert;
+            mAlertParams.mTitle = getText(android.R.string.dialog_alert_title);
+            mAlertParams.mPositiveButtonText = getText(android.R.string.ok);
+            mAlertParams.mPositiveButtonListener = this;
+            mAlertParams.mNegativeButtonText = getText(android.R.string.cancel);
+            mAlertParams.mNegativeButtonListener = this;
+            mAlertParams.mView = view;
+            setupAlert();
 
-            mButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+            getWindow().setCloseOnTouchOutside(false);
+            mButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
             mButton.setEnabled(false);
         } catch (Exception e) {
             Log.e(TAG, "onResume", e);
@@ -87,12 +85,7 @@
     }
 
     @Override
-    protected void onPause() {
-        super.onPause();
-        if (mDialog != null) {
-            mDialog.setOnDismissListener(null);
-            mDialog.dismiss();
-        }
+    public void onBackPressed() {
     }
 
     @Override
@@ -103,16 +96,11 @@
     @Override
     public void onClick(DialogInterface dialog, int which) {
         try {
-            if (which == AlertDialog.BUTTON_POSITIVE && mService.prepareVpn(null, mPackage)) {
+            if (which == DialogInterface.BUTTON_POSITIVE && mService.prepareVpn(null, mPackage)) {
                 setResult(RESULT_OK);
             }
         } catch (Exception e) {
             Log.e(TAG, "onClick", e);
         }
     }
-
-    @Override
-    public void onDismiss(DialogInterface dialog) {
-        finish();
-    }
 }
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 7fb1417..2de0251 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -16,8 +16,6 @@
 
 package com.android.vpndialogs;
 
-import android.app.Activity;
-import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -35,20 +33,20 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.app.AlertActivity;
 import com.android.internal.net.VpnConfig;
 
 import java.io.DataInputStream;
 import java.io.FileInputStream;
 
-public class ManageDialog extends Activity implements Handler.Callback,
-        DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+public class ManageDialog extends AlertActivity implements
+        DialogInterface.OnClickListener, Handler.Callback {
     private static final String TAG = "VpnManage";
 
     private VpnConfig mConfig;
 
     private IConnectivityManager mService;
 
-    private AlertDialog mDialog;
     private TextView mDuration;
     private TextView mDataTransmitted;
     private TextView mDataReceived;
@@ -80,31 +78,24 @@
             mDataReceived = (TextView) view.findViewById(R.id.data_received);
 
             if (mConfig.user.equals(VpnConfig.LEGACY_VPN)) {
-                mDialog = new AlertDialog.Builder(this)
-                        .setIcon(android.R.drawable.ic_dialog_info)
-                        .setTitle(R.string.legacy_title)
-                        .setView(view)
-                        .setNeutralButton(R.string.disconnect, this)
-                        .setNegativeButton(android.R.string.cancel, this)
-                        .create();
+                mAlertParams.mIconId = android.R.drawable.ic_dialog_info;
+                mAlertParams.mTitle = getText(R.string.legacy_title);
             } else {
                 PackageManager pm = getPackageManager();
                 ApplicationInfo app = pm.getApplicationInfo(mConfig.user, 0);
-                mDialog = new AlertDialog.Builder(this)
-                        .setIcon(app.loadIcon(pm))
-                        .setTitle(app.loadLabel(pm))
-                        .setView(view)
-                        .setNeutralButton(R.string.disconnect, this)
-                        .setNegativeButton(android.R.string.cancel, this)
-                        .create();
+                mAlertParams.mIcon = app.loadIcon(pm);
+                mAlertParams.mTitle = app.loadLabel(pm);
             }
-
             if (mConfig.configureIntent != null) {
-                mDialog.setButton(DialogInterface.BUTTON_POSITIVE,
-                        getText(R.string.configure), this);
+                mAlertParams.mPositiveButtonText = getText(R.string.configure);
+                mAlertParams.mPositiveButtonListener = this;
             }
-            mDialog.setOnDismissListener(this);
-            mDialog.show();
+            mAlertParams.mNeutralButtonText = getText(R.string.disconnect);
+            mAlertParams.mNeutralButtonListener = this;
+            mAlertParams.mNegativeButtonText = getText(android.R.string.cancel);
+            mAlertParams.mNegativeButtonListener = this;
+            mAlertParams.mView = view;
+            setupAlert();
 
             if (mHandler == null) {
                 mHandler = new Handler(this);
@@ -119,18 +110,17 @@
     @Override
     protected void onPause() {
         super.onPause();
-        if (mDialog != null) {
-            mDialog.setOnDismissListener(null);
-            mDialog.dismiss();
+        if (!isFinishing()) {
+            finish();
         }
     }
 
     @Override
     public void onClick(DialogInterface dialog, int which) {
         try {
-            if (which == AlertDialog.BUTTON_POSITIVE) {
+            if (which == DialogInterface.BUTTON_POSITIVE) {
                 mConfig.configureIntent.send();
-            } else if (which == AlertDialog.BUTTON_NEUTRAL) {
+            } else if (which == DialogInterface.BUTTON_NEUTRAL) {
                 mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
             }
         } catch (Exception e) {
@@ -140,15 +130,10 @@
     }
 
     @Override
-    public void onDismiss(DialogInterface dialog) {
-        finish();
-    }
-
-    @Override
     public boolean handleMessage(Message message) {
         mHandler.removeMessages(0);
 
-        if (mDialog.isShowing()) {
+        if (!isFinishing()) {
             if (mConfig.startTime != 0) {
                 long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000;
                 mDuration.setText(String.format("%02d:%02d:%02d",
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 38c85bb..bcba3c2 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -16,16 +16,23 @@
 
 package com.android.internal.policy.impl;
 
-import android.app.Activity;
+import com.android.internal.app.ShutdownThread;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.R;
+
+import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.UserInfo;
 import android.media.AudioManager;
 import android.os.Handler;
 import android.os.Message;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.telephony.PhoneStateListener;
@@ -39,13 +46,9 @@
 import android.widget.BaseAdapter;
 import android.widget.ImageView;
 import android.widget.TextView;
-import com.android.internal.R;
-import com.android.internal.app.ShutdownThread;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-import com.google.android.collect.Lists;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Helper to show the global actions dialog.  Each item is an {@link Action} that
@@ -101,9 +104,10 @@
     public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
         mKeyguardShowing = keyguardShowing;
         mDeviceProvisioned = isDeviceProvisioned;
-        if (mDialog == null) {
-            mDialog = createDialog();
+        if (mDialog != null) {
+            mDialog.dismiss();
         }
+        mDialog = createDialog();
         prepareDialog();
 
         mDialog.show();
@@ -187,6 +191,31 @@
             mItems.add(mSilentModeAction);
         }
 
+        List<UserInfo> users = mContext.getPackageManager().getUsers();
+        if (users.size() > 1) {
+            for (final UserInfo user : users) {
+                SinglePressAction switchToUser = new SinglePressAction(
+                        com.android.internal.R.drawable.ic_menu_cc,
+                        user.name != null ? user.name : "Primary") {
+                    public void onPress() {
+                        try {
+                            ActivityManagerNative.getDefault().switchUser(user.id);
+                        } catch (RemoteException re) {
+                            Log.e(TAG, "Couldn't switch user " + re);
+                        }
+                    }
+
+                    public boolean showDuringKeyguard() {
+                        return true;
+                    }
+
+                    public boolean showBeforeProvisioning() {
+                        return false;
+                    }
+                };
+                mItems.add(switchToUser);
+            }
+        }
         mAdapter = new MyAdapter();
 
         final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
@@ -341,12 +370,19 @@
     private static abstract class SinglePressAction implements Action {
         private final int mIconResId;
         private final int mMessageResId;
+        private final CharSequence mMessage;
 
         protected SinglePressAction(int iconResId, int messageResId) {
             mIconResId = iconResId;
             mMessageResId = messageResId;
+            mMessage = null;
         }
 
+        protected SinglePressAction(int iconResId, CharSequence message) {
+            mIconResId = iconResId;
+            mMessageResId = 0;
+            mMessage = message;
+        }
         public boolean isEnabled() {
             return true;
         }
@@ -363,7 +399,11 @@
             v.findViewById(R.id.status).setVisibility(View.GONE);
 
             icon.setImageDrawable(context.getResources().getDrawable(mIconResId));
-            messageView.setText(mMessageResId);
+            if (mMessage != null) {
+                messageView.setText(mMessage);
+            } else {
+                messageView.setText(mMessageResId);
+            }
 
             return v;
         }
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index f45556f..9f3de69 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
@@ -19,6 +19,7 @@
 import com.android.internal.R;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.IccCard.State;
+import com.android.internal.widget.DigitalClock;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.TransportControlView;
 import com.android.internal.policy.impl.KeyguardUpdateMonitor.SimStateCallback;
@@ -105,6 +106,7 @@
     private CharSequence mPlmn;
     private CharSequence mSpn;
     protected int mPhoneState;
+    private DigitalClock mDigitalClock;
 
     private class TransientTextManager {
         private TextView mTextView;
@@ -181,6 +183,7 @@
         mTransportView = (TransportControlView) findViewById(R.id.transport);
         mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton);
         mEmergencyCallButtonEnabledInScreen = emergencyButtonEnabledInScreen;
+        mDigitalClock = (DigitalClock) findViewById(R.id.time);
 
         // Hide transport control view until we know we need to show it.
         if (mTransportView != null) {
@@ -290,6 +293,12 @@
     /** {@inheritDoc} */
     public void onResume() {
         if (DEBUG) Log.v(TAG, "onResume()");
+
+        // First update the clock, if present.
+        if (mDigitalClock != null) {
+            mDigitalClock.updateTime();
+        }
+
         mUpdateMonitor.registerInfoCallback(mInfoCallback);
         mUpdateMonitor.registerSimStateCallback(mSimStateCallback);
         resetStatusInfo();
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 0d0461b..1e9784c 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -855,6 +855,9 @@
             case Password:
                 secure = mLockPatternUtils.isLockPasswordEnabled();
                 break;
+            case Unknown:
+                // This means no security is set up
+                break;
             default:
                 throw new IllegalStateException("unknown unlock mode " + unlockMode);
         }
@@ -877,8 +880,8 @@
 
         // Re-create the unlock screen if necessary. This is primarily required to properly handle
         // SIM state changes. This typically happens when this method is called by reset()
-        if (mode == Mode.UnlockScreen) {
-            final UnlockMode unlockMode = getUnlockMode();
+        final UnlockMode unlockMode = getUnlockMode();
+        if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) {
             if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
                 boolean restartFaceLock = stopFaceLockIfRunning();
                 recreateUnlockScreen(unlockMode);
@@ -1052,11 +1055,15 @@
                     break;
                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
                 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
-                    // "forgot pattern" button is only available in the pattern mode...
-                    if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) {
-                        currentMode = UnlockMode.Account;
+                    if (mLockPatternUtils.isLockPatternEnabled()) {
+                        // "forgot pattern" button is only available in the pattern mode...
+                        if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) {
+                            currentMode = UnlockMode.Account;
+                        } else {
+                            currentMode = UnlockMode.Pattern;
+                        }
                     } else {
-                        currentMode = UnlockMode.Pattern;
+                        currentMode = UnlockMode.Unknown;
                     }
                     break;
                 default:
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 24a2420..3384661 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -23,6 +23,8 @@
 import com.android.internal.widget.multiwaveview.MultiWaveView;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
@@ -34,6 +36,7 @@
 import android.widget.*;
 import android.util.Log;
 import android.media.AudioManager;
+import android.os.RemoteException;
 import android.provider.MediaStore;
 import android.provider.Settings;
 
@@ -229,8 +232,16 @@
                     // Start the Camera
                     Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    mContext.startActivity(intent);
-                    mCallback.goToUnlockScreen();
+                    try {
+                        ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "can't dismiss keyguard on launch");
+                    }
+                    try {
+                        mContext.startActivity(intent);
+                    } catch (ActivityNotFoundException e) {
+                        Log.w(TAG, "Camera application not found");
+                    }
                 } else {
                     toggleRingMode();
                     mUnlockWidgetMethods.updateResources();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
index abed18f..83f7788 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
@@ -52,8 +52,7 @@
     }
 
     public void preDispatchKeyEvent(KeyEvent event) {
-        getAudioManager().preDispatchKeyEvent(event.getKeyCode(),
-                AudioManager.USE_DEFAULT_STREAM_TYPE);
+        getAudioManager().preDispatchKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
     }
 
     public boolean dispatchKeyEvent(KeyEvent event) {
@@ -79,7 +78,7 @@
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                getAudioManager().handleKeyDown(keyCode, AudioManager.USE_DEFAULT_STREAM_TYPE);
+                getAudioManager().handleKeyDown(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
                 return true;
             }
 
@@ -197,8 +196,7 @@
                     AudioManager audioManager = (AudioManager)mContext.getSystemService(
                             Context.AUDIO_SERVICE);
                     if (audioManager != null) {
-                        getAudioManager().handleKeyUp(keyCode,
-                                AudioManager.USE_DEFAULT_STREAM_TYPE);
+                        getAudioManager().handleKeyUp(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
                     }
                 }
                 return true;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index f1fe43b..b87b8c3 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1416,7 +1416,7 @@
                 // doesn't have one of these.  In this case, we execute it here and
                 // eat the event instead, because we have mVolumeControlStreamType
                 // and they don't.
-                getAudioManager().handleKeyDown(keyCode, mVolumeControlStreamType);
+                getAudioManager().handleKeyDown(event, mVolumeControlStreamType);
                 return true;
             }
 
@@ -1478,7 +1478,7 @@
                 // doesn't have one of these.  In this case, we execute it here and
                 // eat the event instead, because we have mVolumeControlStreamType
                 // and they don't.
-                getAudioManager().handleKeyUp(keyCode, mVolumeControlStreamType);
+                getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
                 return true;
             }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 43a34d0..c12a4b7e 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -286,7 +286,8 @@
 
     /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
     boolean mEnableShiftMenuBugReports = false;
-    
+
+    boolean mHeadless;
     boolean mSafeMode;
     WindowState mStatusBar = null;
     boolean mStatusBarCanHide;
@@ -686,7 +687,7 @@
         if (mGlobalActions == null) {
             mGlobalActions = new GlobalActions(mContext);
         }
-        final boolean keyguardShowing = mKeyguardMediator.isShowingAndNotHidden();
+        final boolean keyguardShowing = keyguardIsShowingTq();
         mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
         if (keyguardShowing) {
             // since it took two seconds of long press to bring this up,
@@ -783,7 +784,11 @@
         mWindowManager = windowManager;
         mWindowManagerFuncs = windowManagerFuncs;
         mPowerManager = powerManager;
-        mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
+        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
+        if (!mHeadless) {
+            // don't create KeyguardViewMediator if headless
+            mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
+        }
         mHandler = new Handler();
         mOrientationListener = new MyOrientationListener(mContext);
         try {
@@ -1511,12 +1516,8 @@
     }
     
     static ITelephony getTelephonyService() {
-        ITelephony telephonyService = ITelephony.Stub.asInterface(
+        return ITelephony.Stub.asInterface(
                 ServiceManager.checkService(Context.TELEPHONY_SERVICE));
-        if (telephonyService == null) {
-            Log.w(TAG, "Unable to find ITelephony interface.");
-        }
-        return telephonyService;
     }
 
     static IAudioService getAudioService() {
@@ -1839,7 +1840,7 @@
      * given the situation with the keyguard.
      */
     void launchHomeFromHotKey() {
-        if (mKeyguardMediator.isShowingAndNotHidden()) {
+        if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) {
             // don't launch home if keyguard showing
         } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
             // when in keyguard restricted mode, must first verify unlock
@@ -2044,6 +2045,12 @@
                         mTmpNavigationFrame.offset(mNavigationBarWidth, 0);
                     }
                 }
+                // Make sure the content and current rectangles are updated to
+                // account for the restrictions from the navigation bar.
+                mContentTop = mCurTop = mDockTop;
+                mContentBottom = mCurBottom = mDockBottom;
+                mContentLeft = mCurLeft = mDockLeft;
+                mContentRight = mCurRight = mDockRight;
                 // And compute the final frame.
                 mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
                         mTmpNavigationFrame, mTmpNavigationFrame);
@@ -2383,8 +2390,9 @@
     }
 
     /** {@inheritDoc} */
-    public int finishLayoutLw() {
-        return 0;
+    @Override
+    public void finishLayoutLw() {
+        return;
     }
 
     /** {@inheritDoc} */
@@ -2573,6 +2581,9 @@
 
     /** {@inheritDoc} */
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
+        // do nothing if headless
+        if (mHeadless) return;
+
         // lid changed state
         mLidOpen = lidOpen ? LID_OPEN : LID_CLOSED;
         updateKeyboardVisibility();
@@ -2769,9 +2780,10 @@
         // the same as if it were open and in front.
         // This will prevent any keys other than the power button from waking the screen
         // when the keyguard is hidden by another activity.
-        final boolean keyguardActive = (isScreenOn ?
-                                        mKeyguardMediator.isShowingAndNotHidden() :
-                                        mKeyguardMediator.isShowing());
+        final boolean keyguardActive = (mKeyguardMediator == null ? false :
+                                            (isScreenOn ?
+                                                mKeyguardMediator.isShowingAndNotHidden() :
+                                                mKeyguardMediator.isShowing()));
 
         if (!mSystemBooted) {
             // If we have not yet booted, don't let key events do anything.
@@ -2803,7 +2815,7 @@
         //        the device some other way (which is why we have an exemption here for injected
         //        events).
         int result;
-        if (isScreenOn || (isInjected && !isWakeKey)) {
+        if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) {
             // When the screen is on or if the key is injected pass the key to the application.
             result = ACTION_PASS_TO_USER;
         } else {
@@ -3039,7 +3051,7 @@
         final boolean isWakeMotion = (policyFlags
                 & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
         if (isWakeMotion) {
-            if (mKeyguardMediator.isShowing()) {
+            if (mKeyguardMediator != null && mKeyguardMediator.isShowing()) {
                 // If the keyguard is showing, let it decide what to do with the wake motion.
                 mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
             } else {
@@ -3107,7 +3119,9 @@
             mScreenOnEarly = false;
             mScreenOnFully = false;
         }
-        mKeyguardMediator.onScreenTurnedOff(why);
+        if (mKeyguardMediator != null) {
+            mKeyguardMediator.onScreenTurnedOff(why);
+        }
         synchronized (mLock) {
             updateOrientationListenerLp();
             updateLockScreenTimeout();
@@ -3124,31 +3138,33 @@
             Slog.i(TAG, "Screen turning on...", here);
         }
         if (screenOnListener != null) {
-            mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
-                @Override public void onShown(IBinder windowToken) {
-                    if (windowToken != null) {
-                        try {
-                            mWindowManager.waitForWindowDrawn(windowToken,
-                                    new IRemoteCallback.Stub() {
-                                @Override public void sendResult(Bundle data) {
-                                    Slog.i(TAG, "Lock screen displayed!");
-                                    screenOnListener.onScreenOn();
-                                    synchronized (mLock) {
-                                        mScreenOnFully = true;
+            if (mKeyguardMediator != null) {
+                mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
+                    @Override public void onShown(IBinder windowToken) {
+                        if (windowToken != null) {
+                            try {
+                                mWindowManager.waitForWindowDrawn(windowToken,
+                                        new IRemoteCallback.Stub() {
+                                    @Override public void sendResult(Bundle data) {
+                                        Slog.i(TAG, "Lock screen displayed!");
+                                        screenOnListener.onScreenOn();
+                                        synchronized (mLock) {
+                                            mScreenOnFully = true;
+                                        }
                                     }
-                                }
-                            });
-                        } catch (RemoteException e) {
-                        }
-                    } else {
-                        Slog.i(TAG, "No lock screen!");
-                        screenOnListener.onScreenOn();
-                        synchronized (mLock) {
-                            mScreenOnFully = true;
+                                });
+                            } catch (RemoteException e) {
+                            }
+                        } else {
+                            Slog.i(TAG, "No lock screen!");
+                            screenOnListener.onScreenOn();
+                            synchronized (mLock) {
+                                mScreenOnFully = true;
+                            }
                         }
                     }
-                }
-            });
+                });
+            }
         } else {
             synchronized (mLock) {
                 mScreenOnFully = true;
@@ -3174,15 +3190,20 @@
     
     /** {@inheritDoc} */
     public void enableKeyguard(boolean enabled) {
-        mKeyguardMediator.setKeyguardEnabled(enabled);
+        if (mKeyguardMediator != null) {
+            mKeyguardMediator.setKeyguardEnabled(enabled);
+        }
     }
 
     /** {@inheritDoc} */
     public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
-        mKeyguardMediator.verifyUnlock(callback);
+        if (mKeyguardMediator != null) {
+            mKeyguardMediator.verifyUnlock(callback);
+        }
     }
 
     private boolean keyguardIsShowingTq() {
+        if (mKeyguardMediator == null) return false;
         return mKeyguardMediator.isShowingAndNotHidden();
     }
 
@@ -3194,11 +3215,13 @@
 
     /** {@inheritDoc} */
     public boolean isKeyguardSecure() {
+        if (mKeyguardMediator == null) return false;
         return mKeyguardMediator.isSecure();
     }
 
     /** {@inheritDoc} */
     public boolean inKeyguardRestrictedKeyInputMode() {
+        if (mKeyguardMediator == null) return false;
         return mKeyguardMediator.isInputRestricted();
     }
 
@@ -3454,8 +3477,10 @@
     
     /** {@inheritDoc} */
     public void systemReady() {
-        // tell the keyguard
-        mKeyguardMediator.onSystemReady();
+        if (mKeyguardMediator != null) {
+            // tell the keyguard
+            mKeyguardMediator.onSystemReady();
+        }
         synchronized (mLock) {
             updateOrientationListenerLp();
             mSystemReady = true;
@@ -3478,6 +3503,7 @@
 
     /** {@inheritDoc} */
     public void showBootMessage(final CharSequence msg, final boolean always) {
+        if (mHeadless) return;
         mHandler.post(new Runnable() {
             @Override public void run() {
                 if (mBootMsgDialog == null) {
@@ -3641,7 +3667,9 @@
         public void run() {
             synchronized (this) {
                 if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard");
-                mKeyguardMediator.doKeyguardTimeout();
+                if (mKeyguardMediator != null) {
+                    mKeyguardMediator.doKeyguardTimeout();
+                }
                 mLockScreenTimerActive = false;
             }
         }
@@ -3655,7 +3683,8 @@
 
     private void updateLockScreenTimeout() {
         synchronized (mScreenLockTimeout) {
-            boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly && mKeyguardMediator.isSecure());
+            boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly &&
+                    mKeyguardMediator != null && mKeyguardMediator.isSecure());
             if (mLockScreenTimerActive != enable) {
                 if (enable) {
                     if (localLOGV) Log.v(TAG, "setting lockscreen timer");
@@ -3855,7 +3884,7 @@
 
     public void screenOnStoppedLw() {
         if (mPowerManager.isScreenOn()) {
-            if (!mKeyguardMediator.isShowingAndNotHidden()) {
+            if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
                 long curTime = SystemClock.uptimeMillis();
                 mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
             }
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 52834db..157405a 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -6,9 +6,10 @@
     AudioFlinger.cpp            \
     AudioMixer.cpp.arm          \
     AudioResampler.cpp.arm      \
-    AudioResamplerSinc.cpp.arm  \
-    AudioResamplerCubic.cpp.arm \
-    AudioPolicyService.cpp
+    AudioPolicyService.cpp      \
+    ServiceUtilities.cpp
+#   AudioResamplerSinc.cpp.arm
+#   AudioResamplerCubic.cpp.arm
 
 LOCAL_C_INCLUDES := \
     system/media/audio_effects/include \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index f5892d4..0248687 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioFlinger.cpp
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
@@ -48,6 +48,7 @@
 
 #include "AudioMixer.h"
 #include "AudioFlinger.h"
+#include "ServiceUtilities.h"
 
 #include <media/EffectsFactoryApi.h>
 #include <audio_effects/effect_visualizer.h>
@@ -101,20 +102,6 @@
 
 // ----------------------------------------------------------------------------
 
-static bool recordingAllowed() {
-    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
-    bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO"));
-    if (!ok) ALOGE("Request requires android.permission.RECORD_AUDIO");
-    return ok;
-}
-
-static bool settingsAllowed() {
-    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
-    bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
-    if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
-    return ok;
-}
-
 // To collect the amplifier usage
 static void addBatteryData(uint32_t params) {
     sp<IMediaPlayerService> service = IMediaDeathNotifier::getMediaPlayerService();
@@ -160,7 +147,10 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mPrimaryHardwareDev(NULL), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
+        mPrimaryHardwareDev(NULL),
+        mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef()
+        mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
+        mMode(AUDIO_MODE_INVALID),
         mBtNrecIsOff(false)
 {
 }
@@ -172,7 +162,6 @@
     Mutex::Autolock _l(mLock);
 
     /* TODO: move all this work into an Init() function */
-    mHardwareStatus = AUDIO_HW_IDLE;
 
     for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
         const hw_module_t *mod;
@@ -186,29 +175,32 @@
              mod->name, mod->id);
         mAudioHwDevs.push(dev);
 
-        if (!mPrimaryHardwareDev) {
+        if (mPrimaryHardwareDev == NULL) {
             mPrimaryHardwareDev = dev;
             ALOGI("Using '%s' (%s.%s) as the primary audio interface",
                  mod->name, mod->id, audio_interfaces[i]);
         }
     }
 
-    mHardwareStatus = AUDIO_HW_INIT;
-
-    if (!mPrimaryHardwareDev || mAudioHwDevs.size() == 0) {
+    if (mPrimaryHardwareDev == NULL) {
         ALOGE("Primary audio interface not found");
-        return;
+        // proceed, all later accesses to mPrimaryHardwareDev verify it's safe with initCheck()
     }
 
+    // Currently (mPrimaryHardwareDev == NULL) == (mAudioHwDevs.size() == 0), but the way the
+    // primary HW dev is selected can change so these conditions might not always be equivalent.
+    // When that happens, re-visit all the code that assumes this.
+
+    AutoMutex lock(mHardwareLock);
+
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
         audio_hw_device_t *dev = mAudioHwDevs[i];
 
         mHardwareStatus = AUDIO_HW_INIT;
         rc = dev->init_check(dev);
+        mHardwareStatus = AUDIO_HW_IDLE;
         if (rc == 0) {
-            AutoMutex lock(mHardwareLock);
-
-            mMode = AUDIO_MODE_NORMAL;
+            mMode = AUDIO_MODE_NORMAL;  // assigned multiple times with same value
             mHardwareStatus = AUDIO_HW_SET_MODE;
             dev->set_mode(dev, mMode);
             mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
@@ -218,17 +210,8 @@
     }
 }
 
-status_t AudioFlinger::initCheck() const
-{
-    Mutex::Autolock _l(mLock);
-    if (mPrimaryHardwareDev == NULL || mAudioHwDevs.size() == 0)
-        return NO_INIT;
-    return NO_ERROR;
-}
-
 AudioFlinger::~AudioFlinger()
 {
-    int num_devs = mAudioHwDevs.size();
 
     while (!mRecordThreads.isEmpty()) {
         // closeInput() will remove first entry from mRecordThreads
@@ -239,11 +222,10 @@
         closeOutput(mPlaybackThreads.keyAt(0));
     }
 
-    for (int i = 0; i < num_devs; i++) {
-        audio_hw_device_t *dev = mAudioHwDevs[i];
-        audio_hw_device_close(dev);
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        // no mHardwareLock needed, as there are no other references to this
+        audio_hw_device_close(mAudioHwDevs[i]);
     }
-    mAudioHwDevs.clear();
 }
 
 audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices)
@@ -265,13 +247,10 @@
 
     result.append("Clients:\n");
     for (size_t i = 0; i < mClients.size(); ++i) {
-        wp<Client> wClient = mClients.valueAt(i);
-        if (wClient != 0) {
-            sp<Client> client = wClient.promote();
-            if (client != 0) {
-                snprintf(buffer, SIZE, "  pid: %d\n", client->pid());
-                result.append(buffer);
-            }
+        sp<Client> client = mClients.valueAt(i).promote();
+        if (client != 0) {
+            snprintf(buffer, SIZE, "  pid: %d\n", client->pid());
+            result.append(buffer);
         }
     }
 
@@ -329,7 +308,7 @@
 
 status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
 {
-    if (!checkCallingPermission(String16("android.permission.DUMP"))) {
+    if (!dumpAllowed()) {
         dumpPermissionDenial(fd, args);
     } else {
         // get state of hardware lock
@@ -372,6 +351,18 @@
     return NO_ERROR;
 }
 
+sp<AudioFlinger::Client> AudioFlinger::registerPid_l(pid_t pid)
+{
+    // If pid is already in the mClients wp<> map, then use that entry
+    // (for which promote() is always != 0), otherwise create a new entry and Client.
+    sp<Client> client = mClients.valueFor(pid).promote();
+    if (client == 0) {
+        client = new Client(this, pid);
+        mClients.add(pid, client);
+    }
+
+    return client;
+}
 
 // IAudioFlinger interface
 
@@ -385,14 +376,13 @@
         int frameCount,
         uint32_t flags,
         const sp<IMemory>& sharedBuffer,
-        int output,
+        audio_io_handle_t output,
         int *sessionId,
         status_t *status)
 {
     sp<PlaybackThread::Track> track;
     sp<TrackHandle> trackHandle;
     sp<Client> client;
-    wp<Client> wclient;
     status_t lStatus;
     int lSessionId;
 
@@ -414,14 +404,7 @@
             goto Exit;
         }
 
-        wclient = mClients.valueFor(pid);
-
-        if (wclient != NULL) {
-            client = wclient.promote();
-        } else {
-            client = new Client(this, pid);
-            mClients.add(pid, client);
-        }
+        client = registerPid_l(pid);
 
         ALOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
         if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
@@ -478,7 +461,7 @@
     return trackHandle;
 }
 
-uint32_t AudioFlinger::sampleRate(int output) const
+uint32_t AudioFlinger::sampleRate(audio_io_handle_t output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -489,7 +472,7 @@
     return thread->sampleRate();
 }
 
-int AudioFlinger::channelCount(int output) const
+int AudioFlinger::channelCount(audio_io_handle_t output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -500,7 +483,7 @@
     return thread->channelCount();
 }
 
-audio_format_t AudioFlinger::format(int output) const
+audio_format_t AudioFlinger::format(audio_io_handle_t output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -511,7 +494,7 @@
     return thread->format();
 }
 
-size_t AudioFlinger::frameCount(int output) const
+size_t AudioFlinger::frameCount(audio_io_handle_t output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -522,7 +505,7 @@
     return thread->frameCount();
 }
 
-uint32_t AudioFlinger::latency(int output) const
+uint32_t AudioFlinger::latency(audio_io_handle_t output) const
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -557,7 +540,7 @@
 
     Mutex::Autolock _l(mLock);
     mMasterVolume = value;
-    for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++)
        mPlaybackThreads.valueAt(i)->setMasterVolume(value);
 
     return NO_ERROR;
@@ -589,7 +572,7 @@
     if (NO_ERROR == ret) {
         Mutex::Autolock _l(mLock);
         mMode = mode;
-        for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+        for (size_t i = 0; i < mPlaybackThreads.size(); i++)
            mPlaybackThreads.valueAt(i)->setMode(mode);
     }
 
@@ -623,6 +606,7 @@
     }
 
     bool state = AUDIO_MODE_INVALID;
+    AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
     mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state);
     mHardwareStatus = AUDIO_HW_IDLE;
@@ -637,8 +621,9 @@
     }
 
     Mutex::Autolock _l(mLock);
+    // This is an optimization, so PlaybackThread doesn't have to look at the one from AudioFlinger
     mMasterMute = muted;
-    for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++)
        mPlaybackThreads.valueAt(i)->setMasterMute(muted);
 
     return NO_ERROR;
@@ -656,7 +641,8 @@
     return masterMute_l();
 }
 
-status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, int output)
+status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
+        audio_io_handle_t output)
 {
     // check calling permissions
     if (!settingsAllowed()) {
@@ -680,7 +666,7 @@
     mStreamTypes[stream].volume = value;
 
     if (thread == NULL) {
-        for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
+        for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
            mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
         }
     } else {
@@ -711,7 +697,7 @@
     return NO_ERROR;
 }
 
-float AudioFlinger::streamVolume(audio_stream_type_t stream, int output) const
+float AudioFlinger::streamVolume(audio_stream_type_t stream, audio_io_handle_t output) const
 {
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
         return 0.0f;
@@ -726,7 +712,7 @@
         }
         volume = thread->streamVolume(stream);
     } else {
-        volume = mStreamTypes[stream].volume;
+        volume = streamVolume_l(stream);
     }
 
     return volume;
@@ -738,14 +724,15 @@
         return true;
     }
 
-    return mStreamTypes[stream].mute;
+    AutoMutex lock(mLock);
+    return streamMute_l(stream);
 }
 
-status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)
+status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
 {
     status_t result;
 
-    ALOGV("setParameters(): io %d, keyvalue %s, tid %d, calling tid %d",
+    ALOGV("setParameters(): io %d, keyvalue %s, tid %d, calling pid %d",
             ioHandle, keyValuePairs.string(), gettid(), IPCThreadState::self()->getCallingPid());
     // check calling permissions
     if (!settingsAllowed()) {
@@ -810,16 +797,15 @@
             }
         }
     }
-    if (thread != NULL) {
-        result = thread->setParameters(keyValuePairs);
-        return result;
+    if (thread != 0) {
+        return thread->setParameters(keyValuePairs);
     }
     return BAD_VALUE;
 }
 
-String8 AudioFlinger::getParameters(int ioHandle, const String8& keys)
+String8 AudioFlinger::getParameters(audio_io_handle_t ioHandle, const String8& keys) const
 {
-//    ALOGV("getParameters() io %d, keys %s, tid %d, calling tid %d",
+//    ALOGV("getParameters() io %d, keys %s, tid %d, calling pid %d",
 //            ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
 
     if (ioHandle == 0) {
@@ -847,17 +833,21 @@
     return String8("");
 }
 
-size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount)
+size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const
 {
     status_t ret = initCheck();
     if (ret != NO_ERROR) {
         return 0;
     }
 
-    return mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+    AutoMutex lock(mHardwareLock);
+    mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
+    size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    return size;
 }
 
-unsigned int AudioFlinger::getInputFramesLost(int ioHandle)
+unsigned int AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const
 {
     if (ioHandle == 0) {
         return 0;
@@ -892,7 +882,8 @@
     return ret;
 }
 
-status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output)
+status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
+        audio_io_handle_t output) const
 {
     status_t status;
 
@@ -911,7 +902,7 @@
 
     Mutex::Autolock _l(mLock);
 
-    int pid = IPCThreadState::self()->getCallingPid();
+    pid_t pid = IPCThreadState::self()->getCallingPid();
     if (mNotificationClients.indexOfKey(pid) < 0) {
         sp<NotificationClient> notificationClient = new NotificationClient(this,
                                                                             client,
@@ -939,7 +930,7 @@
 {
     Mutex::Autolock _l(mLock);
 
-    int index = mNotificationClients.indexOfKey(pid);
+    ssize_t index = mNotificationClients.indexOfKey(pid);
     if (index >= 0) {
         sp <NotificationClient> client = mNotificationClients.valueFor(pid);
         ALOGV("removeNotificationClient() %p, pid %d", client.get(), pid);
@@ -947,9 +938,9 @@
     }
 
     ALOGV("%d died, releasing its sessions", pid);
-    int num = mAudioSessionRefs.size();
+    size_t num = mAudioSessionRefs.size();
     bool removed = false;
-    for (int i = 0; i< num; i++) {
+    for (size_t i = 0; i< num; ) {
         AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
         ALOGV(" pid %d @ %d", ref->pid, i);
         if (ref->pid == pid) {
@@ -957,8 +948,9 @@
             mAudioSessionRefs.removeAt(i);
             delete ref;
             removed = true;
-            i--;
             num--;
+        } else {
+            i++;
         }
     }
     if (removed) {
@@ -967,11 +959,12 @@
 }
 
 // audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2)
+void AudioFlinger::audioConfigChanged_l(int event, audio_io_handle_t ioHandle, void *param2)
 {
     size_t size = mNotificationClients.size();
     for (size_t i = 0; i < size; i++) {
-        mNotificationClients.valueAt(i)->client()->ioConfigChanged(event, ioHandle, param2);
+        mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioHandle,
+                                                                               param2);
     }
 }
 
@@ -985,13 +978,19 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device)
+AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
+        uint32_t device, type_t type)
     :   Thread(false),
-        mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
-        mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID), mStandby(false), mId(id), mExiting(false),
-        mDevice(device)
+        mType(type),
+        mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0),
+        // mChannelMask
+        mChannelCount(0),
+        mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID),
+        mParamStatus(NO_ERROR),
+        mStandby(false), mId(id),
+        mDevice(device),
+        mDeathRecipient(new PMDeathRecipient(this))
 {
-    mDeathRecipient = new PMDeathRecipient(this);
 }
 
 AudioFlinger::ThreadBase::~ThreadBase()
@@ -1007,40 +1006,26 @@
 
 void AudioFlinger::ThreadBase::exit()
 {
-    // keep a strong ref on ourself so that we won't get
-    // destroyed in the middle of requestExitAndWait()
-    sp <ThreadBase> strongMe = this;
-
     ALOGV("ThreadBase::exit");
     {
+        // This lock prevents the following race in thread (uniprocessor for illustration):
+        //  if (!exitPending()) {
+        //      // context switch from here to exit()
+        //      // exit() calls requestExit(), what exitPending() observes
+        //      // exit() calls signal(), which is dropped since no waiters
+        //      // context switch back from exit() to here
+        //      mWaitWorkCV.wait(...);
+        //      // now thread is hung
+        //  }
         AutoMutex lock(mLock);
-        mExiting = true;
         requestExit();
         mWaitWorkCV.signal();
     }
+    // When Thread::requestExitAndWait is made virtual and this method is renamed to
+    // "virtual status_t requestExitAndWait()", replace by "return Thread::requestExitAndWait();"
     requestExitAndWait();
 }
 
-uint32_t AudioFlinger::ThreadBase::sampleRate() const
-{
-    return mSampleRate;
-}
-
-int AudioFlinger::ThreadBase::channelCount() const
-{
-    return (int)mChannelCount;
-}
-
-audio_format_t AudioFlinger::ThreadBase::format() const
-{
-    return mFormat;
-}
-
-size_t AudioFlinger::ThreadBase::frameCount() const
-{
-    return mFrameCount;
-}
-
 status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
 {
     status_t status;
@@ -1242,8 +1227,7 @@
 void AudioFlinger::ThreadBase::setEffectSuspended_l(
         const effect_uuid_t *type, bool suspend, int sessionId)
 {
-    sp<EffectChain> chain;
-    chain = getEffectChain_l(sessionId);
+    sp<EffectChain> chain = getEffectChain_l(sessionId);
     if (chain != 0) {
         if (type != NULL) {
             chain->setEffectSuspended_l(type, suspend);
@@ -1257,7 +1241,7 @@
 
 void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain)
 {
-    int index = mSuspendedSessions.indexOfKey(chain->sessionId());
+    ssize_t index = mSuspendedSessions.indexOfKey(chain->sessionId());
     if (index < 0) {
         return;
     }
@@ -1283,7 +1267,7 @@
                                                          bool suspend,
                                                          int sessionId)
 {
-    int index = mSuspendedSessions.indexOfKey(sessionId);
+    ssize_t index = mSuspendedSessions.indexOfKey(sessionId);
 
     KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects;
 
@@ -1371,30 +1355,36 @@
 
 AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
                                              AudioStreamOut* output,
-                                             int id,
-                                             uint32_t device)
-    :   ThreadBase(audioFlinger, id, device),
-        mMixBuffer(NULL), mSuspended(0), mBytesWritten(0), mOutput(output),
+                                             audio_io_handle_t id,
+                                             uint32_t device,
+                                             type_t type)
+    :   ThreadBase(audioFlinger, id, device, type),
+        mMixBuffer(NULL), mSuspended(0), mBytesWritten(0),
+        // Assumes constructor is called by AudioFlinger with it's mLock held,
+        // but it would be safer to explicitly pass initial masterMute as parameter
+        mMasterMute(audioFlinger->masterMute_l()),
+        // mStreamTypes[] initialized in constructor body
+        mOutput(output),
+        // Assumes constructor is called by AudioFlinger with it's mLock held,
+        // but it would be safer to explicitly pass initial masterVolume as parameter
+        mMasterVolume(audioFlinger->masterVolume_l()),
         mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
 {
     snprintf(mName, kNameLength, "AudioOut_%d", id);
 
     readOutputParameters();
 
-    // Assumes constructor is called by AudioFlinger with it's mLock held,
-    // but it would be safer to explicitly pass these as parameters
-    mMasterVolume = mAudioFlinger->masterVolume_l();
-    mMasterMute = mAudioFlinger->masterMute_l();
-
     // mStreamTypes[AUDIO_STREAM_CNT] is initialized by stream_type_t default constructor
     // There is no AUDIO_STREAM_MIN, and ++ operator does not compile
     for (audio_stream_type_t stream = (audio_stream_type_t) 0; stream < AUDIO_STREAM_CNT;
             stream = (audio_stream_type_t) (stream + 1)) {
-        mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream);
-        mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream);
+        mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
+        mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
         // initialized by stream_type_t default constructor
         // mStreamTypes[stream].valid = true;
     }
+    // mStreamTypes[AUDIO_STREAM_CNT] exists but isn't explicitly initialized here,
+    // because mAudioFlinger doesn't have one to copy from
 }
 
 AudioFlinger::PlaybackThread::~PlaybackThread()
@@ -1431,13 +1421,10 @@
     result.append(buffer);
     result.append("   Name  Clien Typ Fmt Chn mask   Session Buf  S M F SRate LeftV RighV  Serv       User       Main buf   Aux Buf\n");
     for (size_t i = 0; i < mActiveTracks.size(); ++i) {
-        wp<Track> wTrack = mActiveTracks[i];
-        if (wTrack != 0) {
-            sp<Track> track = wTrack.promote();
-            if (track != 0) {
-                track->dump(buffer, SIZE);
-                result.append(buffer);
-            }
+        sp<Track> track = mActiveTracks[i].promote();
+        if (track != 0) {
+            track->dump(buffer, SIZE);
+            result.append(buffer);
         }
     }
     write(fd, result.string(), result.size());
@@ -1534,12 +1521,11 @@
         // all tracks in same audio session must share the same routing strategy otherwise
         // conflicts will happen when tracks are moved from one output to another by audio policy
         // manager
-        uint32_t strategy =
-                AudioSystem::getStrategyForStream((audio_stream_type_t)streamType);
+        uint32_t strategy = AudioSystem::getStrategyForStream(streamType);
         for (size_t i = 0; i < mTracks.size(); ++i) {
             sp<Track> t = mTracks[i];
             if (t != 0) {
-                uint32_t actual = AudioSystem::getStrategyForStream((audio_stream_type_t)t->type());
+                uint32_t actual = AudioSystem::getStrategyForStream(t->streamType());
                 if (sessionId == t->sessionId() && strategy != actual) {
                     ALOGE("createTrack_l() mismatched strategy; expected %u but found %u",
                             strategy, actual);
@@ -1561,7 +1547,7 @@
         if (chain != 0) {
             ALOGV("createTrack_l() setting main buffer %p", chain->inBuffer());
             track->setMainBuffer(chain->inBuffer());
-            chain->setStrategy(AudioSystem::getStrategyForStream((audio_stream_type_t)track->type()));
+            chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType()));
             chain->incTrackCnt();
         }
 
@@ -1592,50 +1578,36 @@
     }
 }
 
-status_t AudioFlinger::PlaybackThread::setMasterVolume(float value)
+void AudioFlinger::PlaybackThread::setMasterVolume(float value)
 {
+    Mutex::Autolock _l(mLock);
     mMasterVolume = value;
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted)
+void AudioFlinger::PlaybackThread::setMasterMute(bool muted)
 {
-    mMasterMute = muted;
-    return NO_ERROR;
+    Mutex::Autolock _l(mLock);
+    setMasterMute_l(muted);
 }
 
-float AudioFlinger::PlaybackThread::masterVolume() const
+void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
 {
-    return mMasterVolume;
-}
-
-bool AudioFlinger::PlaybackThread::masterMute() const
-{
-    return mMasterMute;
-}
-
-status_t AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
-{
+    Mutex::Autolock _l(mLock);
     mStreamTypes[stream].volume = value;
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted)
+void AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted)
 {
+    Mutex::Autolock _l(mLock);
     mStreamTypes[stream].mute = muted;
-    return NO_ERROR;
 }
 
 float AudioFlinger::PlaybackThread::streamVolume(audio_stream_type_t stream) const
 {
+    Mutex::Autolock _l(mLock);
     return mStreamTypes[stream].volume;
 }
 
-bool AudioFlinger::PlaybackThread::streamMute(audio_stream_type_t stream) const
-{
-    return mStreamTypes[stream].mute;
-}
-
 // addTrack_l() must be called with ThreadBase::mLock held
 status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
 {
@@ -1705,7 +1677,7 @@
 // audioConfigChanged_l() must be called with AudioFlinger::mLock held
 void AudioFlinger::PlaybackThread::audioConfigChanged_l(int event, int param) {
     AudioSystem::OutputDescriptor desc;
-    void *param2 = 0;
+    void *param2 = NULL;
 
     ALOGV("PlaybackThread::audioConfigChanged_l, thread %p, event %d, param %d", this, event, param);
 
@@ -1740,7 +1712,7 @@
 
     // FIXME - Current mixer implementation only supports stereo output: Always
     // Allocate a stereo buffer even if HW output is mono.
-    if (mMixBuffer != NULL) delete[] mMixBuffer;
+    delete[] mMixBuffer;
     mMixBuffer = new int16_t[mFrameCount * 2];
     memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
 
@@ -1758,7 +1730,7 @@
 
 status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames)
 {
-    if (halFrames == 0 || dspFrames == 0) {
+    if (halFrames == NULL || dspFrames == NULL) {
         return BAD_VALUE;
     }
     Mutex::Autolock _l(mLock);
@@ -1801,14 +1773,14 @@
         sp<Track> track = mTracks[i];
         if (sessionId == track->sessionId() &&
                 !(track->mCblk->flags & CBLK_INVALID_MSK)) {
-            return AudioSystem::getStrategyForStream((audio_stream_type_t) track->type());
+            return AudioSystem::getStrategyForStream(track->streamType());
         }
     }
     return AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
 }
 
 
-AudioFlinger::AudioStreamOut* AudioFlinger::PlaybackThread::getOutput()
+AudioFlinger::AudioStreamOut* AudioFlinger::PlaybackThread::getOutput() const
 {
     Mutex::Autolock _l(mLock);
     return mOutput;
@@ -1845,13 +1817,12 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
-    :   PlaybackThread(audioFlinger, output, id, device),
-        mAudioMixer(NULL), mPrevMixerStatus(MIXER_IDLE)
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
+        audio_io_handle_t id, uint32_t device, type_t type)
+    :   PlaybackThread(audioFlinger, output, id, device, type),
+        mAudioMixer(new AudioMixer(mFrameCount, mSampleRate)),
+        mPrevMixerStatus(MIXER_IDLE)
 {
-    mType = ThreadBase::MIXER;
-    mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
-
     // FIXME - Current mixer implementation only supports stereo output
     if (mChannelCount == 1) {
         ALOGE("Invalid audio hardware channel count");
@@ -1866,7 +1837,7 @@
 bool AudioFlinger::MixerThread::threadLoop()
 {
     Vector< sp<Track> > tracksToRemove;
-    uint32_t mixerStatus = MIXER_IDLE;
+    mixer_state mixerStatus = MIXER_IDLE;
     nsecs_t standbyTime = systemTime();
     size_t mixBufferSize = mFrameCount * mFrameSize;
     // FIXME: Relaxed timing because of a certain device that can't meet latency
@@ -1941,7 +1912,7 @@
             if (CC_UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) ||
                         mSuspended)) {
                 if (!mStandby) {
-                    ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d\n", this, mSuspended);
+                    ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d", this, mSuspended);
                     mOutput->stream->common.standby(&mOutput->stream->common);
                     mStandby = true;
                     mBytesWritten = 0;
@@ -1955,9 +1926,9 @@
 
                     releaseWakeLock_l();
                     // wait until we have something to do...
-                    ALOGV("MixerThread %p TID %d going to sleep\n", this, gettid());
+                    ALOGV("MixerThread %p TID %d going to sleep", this, gettid());
                     mWaitWorkCV.wait(mLock);
-                    ALOGV("MixerThread %p TID %d waking up\n", this, gettid());
+                    ALOGV("MixerThread %p TID %d waking up", this, gettid());
                     acquireWakeLock_l();
 
                     mPrevMixerStatus = MIXER_IDLE;
@@ -1966,7 +1937,7 @@
                         property_get("ro.audio.silent", value, "0");
                         if (atoi(value)) {
                             ALOGD("Silence is golden");
-                            setMasterMute(true);
+                            setMasterMute_l(true);
                         }
                     }
 
@@ -1988,11 +1959,14 @@
         if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
             // mix buffers...
             mAudioMixer->process();
-            sleepTime = 0;
-            // increase sleep time progressively when application underrun condition clears
-            if (sleepTimeShift > 0) {
+            // increase sleep time progressively when application underrun condition clears.
+            // Only increase sleep time if the mixer is ready for two consecutive times to avoid
+            // that a steady state of alternating ready/not ready conditions keeps the sleep time
+            // such that we would underrun the audio HAL.
+            if ((sleepTime == 0) && (sleepTimeShift > 0)) {
                 sleepTimeShift--;
             }
+            sleepTime = 0;
             standbyTime = systemTime() + kStandbyTimeInNsecs;
             //TODO: delay standby when effects have a tail
         } else {
@@ -2082,10 +2056,11 @@
 }
 
 // prepareTracks_l() must be called with ThreadBase::mLock held
-uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
+AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
+        const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
 {
 
-    uint32_t mixerStatus = MIXER_IDLE;
+    mixer_state mixerStatus = MIXER_IDLE;
     // find out which tracks need to be processed
     size_t count = activeTracks.size();
     size_t mixedTracks = 0;
@@ -2179,7 +2154,7 @@
             // compute volume for this track
             uint32_t vl, vr, va;
             if (track->isMuted() || track->isPausing() ||
-                mStreamTypes[track->type()].mute) {
+                mStreamTypes[track->streamType()].mute) {
                 vl = vr = va = 0;
                 if (track->isPausing()) {
                     track->setPaused();
@@ -2187,9 +2162,9 @@
             } else {
 
                 // read original volumes with volume control
-                float typeVolume = mStreamTypes[track->type()].volume;
+                float typeVolume = mStreamTypes[track->streamType()].volume;
                 float v = masterVolume * typeVolume;
-                uint32_t vlr = cblk->volumeLR;
+                uint32_t vlr = cblk->getVolumeLR();
                 vl = vlr & 0xFFFF;
                 vr = vlr >> 16;
                 // track volumes come from shared memory, so can't be trusted and must be clamped
@@ -2348,7 +2323,7 @@
     size_t size = mTracks.size();
     for (size_t i = 0; i < size; i++) {
         sp<Track> t = mTracks[i];
-        if (t->type() == streamType) {
+        if (t->streamType() == streamType) {
             android_atomic_or(CBLK_INVALID_ON, &t->mCblk->flags);
             t->mCblk->cv.signal();
         }
@@ -2457,6 +2432,8 @@
             }
             if (status == NO_ERROR && reconfig) {
                 delete mAudioMixer;
+                // for safety in case readOutputParameters() accesses mAudioMixer (it doesn't)
+                mAudioMixer = NULL;
                 readOutputParameters();
                 mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
                 for (size_t i = 0; i < mTracks.size() ; i++) {
@@ -2508,31 +2485,18 @@
 }
 
 // ----------------------------------------------------------------------------
-AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
-    :   PlaybackThread(audioFlinger, output, id, device)
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
+        AudioStreamOut* output, audio_io_handle_t id, uint32_t device)
+    :   PlaybackThread(audioFlinger, output, id, device, DIRECT)
+        // mLeftVolFloat, mRightVolFloat
+        // mLeftVolShort, mRightVolShort
 {
-    mType = ThreadBase::DIRECT;
 }
 
 AudioFlinger::DirectOutputThread::~DirectOutputThread()
 {
 }
 
-static inline
-int32_t mul(int16_t in, int16_t v)
-{
-#if defined(__arm__) && !defined(__thumb__)
-    int32_t out;
-    asm( "smulbb %[out], %[in], %[v] \n"
-         : [out]"=r"(out)
-         : [in]"%r"(in), [v]"r"(v)
-         : );
-    return out;
-#else
-    return in * int32_t(v);
-#endif
-}
-
 void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp)
 {
     // Do not apply volume on compressed audio
@@ -2609,7 +2573,7 @@
 
 bool AudioFlinger::DirectOutputThread::threadLoop()
 {
-    uint32_t mixerStatus = MIXER_IDLE;
+    mixer_state mixerStatus = MIXER_IDLE;
     sp<Track> trackToRemove;
     sp<Track> activeTrack;
     nsecs_t standbyTime = systemTime();
@@ -2651,7 +2615,7 @@
                         mSuspended)) {
                 // wait until we have something to do...
                 if (!mStandby) {
-                    ALOGV("Audio hardware entering standby, mixer %p\n", this);
+                    ALOGV("Audio hardware entering standby, mixer %p", this);
                     mOutput->stream->common.standby(&mOutput->stream->common);
                     mStandby = true;
                     mBytesWritten = 0;
@@ -2664,9 +2628,9 @@
                     if (exitPending()) break;
 
                     releaseWakeLock_l();
-                    ALOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid());
+                    ALOGV("DirectOutputThread %p TID %d going to sleep", this, gettid());
                     mWaitWorkCV.wait(mLock);
-                    ALOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid());
+                    ALOGV("DirectOutputThread %p TID %d waking up in active mode", this, gettid());
                     acquireWakeLock_l();
 
                     if (!mMasterMute) {
@@ -2674,7 +2638,7 @@
                         property_get("ro.audio.silent", value, "0");
                         if (atoi(value)) {
                             ALOGD("Silence is golden");
-                            setMasterMute(true);
+                            setMasterMute_l(true);
                         }
                     }
 
@@ -2717,15 +2681,15 @@
                     // compute volume for this track
                     float left, right;
                     if (track->isMuted() || mMasterMute || track->isPausing() ||
-                        mStreamTypes[track->type()].mute) {
+                        mStreamTypes[track->streamType()].mute) {
                         left = right = 0;
                         if (track->isPausing()) {
                             track->setPaused();
                         }
                     } else {
-                        float typeVolume = mStreamTypes[track->type()].volume;
+                        float typeVolume = mStreamTypes[track->streamType()].volume;
                         float v = mMasterVolume * typeVolume;
-                        uint32_t vlr = cblk->volumeLR;
+                        uint32_t vlr = cblk->getVolumeLR();
                         float v_clamped = v * (vlr & 0xFFFF);
                         if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
                         left = v_clamped/MAX_GAIN;
@@ -2988,10 +2952,11 @@
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
-    :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX)
+AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
+        AudioFlinger::MixerThread* mainThread, audio_io_handle_t id)
+    :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device(), DUPLICATING),
+        mWaitTimeMs(UINT_MAX)
 {
-    mType = ThreadBase::DUPLICATING;
     addOutputTrack(mainThread);
 }
 
@@ -3000,13 +2965,12 @@
     for (size_t i = 0; i < mOutputTracks.size(); i++) {
         mOutputTracks[i]->destroy();
     }
-    mOutputTracks.clear();
 }
 
 bool AudioFlinger::DuplicatingThread::threadLoop()
 {
     Vector< sp<Track> > tracksToRemove;
-    uint32_t mixerStatus = MIXER_IDLE;
+    mixer_state mixerStatus = MIXER_IDLE;
     nsecs_t standbyTime = systemTime();
     size_t mixBufferSize = mFrameCount*mFrameSize;
     SortedVector< sp<OutputTrack> > outputTracks;
@@ -3059,9 +3023,9 @@
                     if (exitPending()) break;
 
                     releaseWakeLock_l();
-                    ALOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid());
+                    ALOGV("DuplicatingThread %p TID %d going to sleep", this, gettid());
                     mWaitWorkCV.wait(mLock);
-                    ALOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
+                    ALOGV("DuplicatingThread %p TID %d waking up", this, gettid());
                     acquireWakeLock_l();
 
                     mPrevMixerStatus = MIXER_IDLE;
@@ -3070,7 +3034,7 @@
                         property_get("ro.audio.silent", value, "0");
                         if (atoi(value)) {
                             ALOGD("Silence is golden");
-                            setMasterMute(true);
+                            setMasterMute_l(true);
                         }
                     }
 
@@ -3158,6 +3122,7 @@
 
 void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
 {
+    // FIXME explain this formula
     int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate();
     OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread,
                                             this,
@@ -3192,7 +3157,7 @@
     mWaitTimeMs = UINT_MAX;
     for (size_t i = 0; i < mOutputTracks.size(); i++) {
         sp<ThreadBase> strong = mOutputTracks[i]->thread().promote();
-        if (strong != NULL) {
+        if (strong != 0) {
             uint32_t waitTimeMs = (strong->frameCount() * 2 * 1000) / strong->sampleRate();
             if (waitTimeMs < mWaitTimeMs) {
                 mWaitTimeMs = waitTimeMs;
@@ -3240,13 +3205,16 @@
     :   RefBase(),
         mThread(thread),
         mClient(client),
-        mCblk(0),
+        mCblk(NULL),
+        // mBuffer
+        // mBufferEnd
         mFrameCount(0),
         mState(IDLE),
-        mClientTid(-1),
         mFormat(format),
         mFlags(flags & ~SYSTEM_FLAGS_MASK),
         mSessionId(sessionId)
+        // mChannelCount
+        // mChannelMask
 {
     ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
 
@@ -3262,7 +3230,7 @@
         mCblkMemory = client->heap()->allocate(size);
         if (mCblkMemory != 0) {
             mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
-            if (mCblk) { // construct the shared structure in-place.
+            if (mCblk != NULL) { // construct the shared structure in-place.
                 new(mCblk) audio_track_cblk_t();
                 // clear all buffers
                 mCblk->frameCount = frameCount;
@@ -3305,15 +3273,20 @@
 
 AudioFlinger::ThreadBase::TrackBase::~TrackBase()
 {
-    if (mCblk) {
-        mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
-        if (mClient == NULL) {
+    if (mCblk != NULL) {
+        if (mClient == 0) {
             delete mCblk;
+        } else {
+            mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
         }
     }
-    mCblkMemory.clear();            // and free the shared memory
-    if (mClient != NULL) {
+    mCblkMemory.clear();    // free the shared memory before releasing the heap it belongs to
+    if (mClient != 0) {
+        // Client destructor must run with AudioFlinger mutex locked
         Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+        // If the client's reference count drops to zero, the associated destructor
+        // must run with AudioFlinger lock held. Thus the explicit clear() rather than
+        // relying on the automatic clear() at end of scope.
         mClient.clear();
     }
 }
@@ -3349,23 +3322,10 @@
     ALOGV("TrackBase::reset");
 }
 
-sp<IMemory> AudioFlinger::ThreadBase::TrackBase::getCblk() const
-{
-    return mCblkMemory;
-}
-
 int AudioFlinger::ThreadBase::TrackBase::sampleRate() const {
     return (int)mCblk->sampleRate;
 }
 
-int AudioFlinger::ThreadBase::TrackBase::channelCount() const {
-    return (const int)mChannelCount;
-}
-
-uint32_t AudioFlinger::ThreadBase::TrackBase::channelMask() const {
-    return mChannelMask;
-}
-
 void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
     audio_track_cblk_t* cblk = this->cblk();
     size_t frameSize = cblk->frameSize;
@@ -3379,7 +3339,7 @@
                 server %d, serverBase %d, user %d, userBase %d",
                 bufferStart, bufferEnd, mBuffer, mBufferEnd,
                 cblk->server, cblk->serverBase, cblk->user, cblk->userBase);
-        return 0;
+        return NULL;
     }
 
     return bufferStart;
@@ -3409,7 +3369,7 @@
             mName = playbackThread->getTrackName_l();
             mMainBuffer = playbackThread->mixBuffer();
         }
-        ALOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+        ALOGV("Track constructor name %d, calling pid %d", mName, IPCThreadState::self()->getCallingPid());
         if (mName < 0) {
             ALOGE("no more track names available");
         }
@@ -3434,7 +3394,7 @@
 {
     // NOTE: destroyTrack_l() can remove a strong reference to this Track
     // by removing it from mTracks vector, so there is a risk that this Tracks's
-    // desctructor is called. As the destructor needs to lock mLock,
+    // destructor is called. As the destructor needs to lock mLock,
     // we must acquire a strong reference on this Track before locking mLock
     // here so that the destructor is called only when exiting this function.
     // On the other hand, as long as Track::destroy() is only called by
@@ -3446,9 +3406,7 @@
         if (thread != 0) {
             if (!isOutputTrack()) {
                 if (mState == ACTIVE || mState == RESUMING) {
-                    AudioSystem::stopOutput(thread->id(),
-                                            (audio_stream_type_t)mStreamType,
-                                            mSessionId);
+                    AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId);
 
                     // to track the speaker usage
                     addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
@@ -3464,10 +3422,10 @@
 
 void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
 {
-    uint32_t vlr = mCblk->volumeLR;
+    uint32_t vlr = mCblk->getVolumeLR();
     snprintf(buffer, size, "   %05d %05d %03u %03u 0x%08x %05u   %04u %1d %1d %1d %05u %05u %05u  0x%08x 0x%08x 0x%08x 0x%08x\n",
             mName - AudioMixer::TRACK0,
-            (mClient == NULL) ? getpid() : mClient->pid(),
+            (mClient == 0) ? getpid_cached : mClient->pid(),
             mStreamType,
             mFormat,
             mChannelMask,
@@ -3538,15 +3496,15 @@
     return false;
 }
 
-status_t AudioFlinger::PlaybackThread::Track::start()
+status_t AudioFlinger::PlaybackThread::Track::start(pid_t tid)
 {
     status_t status = NO_ERROR;
-    ALOGV("start(%d), calling thread %d session %d",
-            mName, IPCThreadState::self()->getCallingPid(), mSessionId);
+    ALOGV("start(%d), calling pid %d session %d tid %d",
+            mName, IPCThreadState::self()->getCallingPid(), mSessionId, tid);
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
-        int state = mState;
+        track_state state = mState;
         // here the track could be either new, or restarted
         // in both cases "unstop" the track
         if (mState == PAUSED) {
@@ -3559,9 +3517,7 @@
 
         if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
             thread->mLock.unlock();
-            status = AudioSystem::startOutput(thread->id(),
-                                              (audio_stream_type_t)mStreamType,
-                                              mSessionId);
+            status = AudioSystem::startOutput(thread->id(), mStreamType, mSessionId);
             thread->mLock.lock();
 
             // to track the speaker usage
@@ -3583,11 +3539,11 @@
 
 void AudioFlinger::PlaybackThread::Track::stop()
 {
-    ALOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+    ALOGV("stop(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid());
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
-        int state = mState;
+        track_state state = mState;
         if (mState > STOPPED) {
             mState = STOPPED;
             // If the track is not active (PAUSED and buffers full), flush buffers
@@ -3599,9 +3555,7 @@
         }
         if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) {
             thread->mLock.unlock();
-            AudioSystem::stopOutput(thread->id(),
-                                    (audio_stream_type_t)mStreamType,
-                                    mSessionId);
+            AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId);
             thread->mLock.lock();
 
             // to track the speaker usage
@@ -3612,7 +3566,7 @@
 
 void AudioFlinger::PlaybackThread::Track::pause()
 {
-    ALOGV("pause(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+    ALOGV("pause(%d), calling pid %d", mName, IPCThreadState::self()->getCallingPid());
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
@@ -3621,9 +3575,7 @@
             ALOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get());
             if (!isOutputTrack()) {
                 thread->mLock.unlock();
-                AudioSystem::stopOutput(thread->id(),
-                                        (audio_stream_type_t)mStreamType,
-                                        mSessionId);
+                AudioSystem::stopOutput(thread->id(), mStreamType, mSessionId);
                 thread->mLock.lock();
 
                 // to track the speaker usage
@@ -3767,12 +3719,12 @@
     return NOT_ENOUGH_DATA;
 }
 
-status_t AudioFlinger::RecordThread::RecordTrack::start()
+status_t AudioFlinger::RecordThread::RecordTrack::start(pid_t tid)
 {
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         RecordThread *recordThread = (RecordThread *)thread.get();
-        return recordThread->start(this);
+        return recordThread->start(this, tid);
     } else {
         return BAD_VALUE;
     }
@@ -3794,7 +3746,7 @@
 void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
 {
     snprintf(buffer, size, "   %05d %03u 0x%08x %05d   %04u %01d %05u  %08x %08x\n",
-            (mClient == NULL) ? getpid() : mClient->pid(),
+            (mClient == 0) ? getpid_cached : mClient->pid(),
             mFormat,
             mChannelMask,
             mSessionId,
@@ -3823,7 +3775,6 @@
     if (mCblk != NULL) {
         mCblk->flags |= CBLK_DIRECTION_OUT;
         mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
-        mCblk->volumeLR = (MAX_GAIN_INT << 16) | MAX_GAIN_INT;
         mOutBuffer.frameCount = 0;
         playbackThread->mTracks.add(this);
         ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, " \
@@ -3840,9 +3791,9 @@
     clearBufferQueue();
 }
 
-status_t AudioFlinger::PlaybackThread::OutputTrack::start()
+status_t AudioFlinger::PlaybackThread::OutputTrack::start(pid_t tid)
 {
-    status_t status = Track::start();
+    status_t status = Track::start(tid);
     if (status != NO_ERROR) {
         return status;
     }
@@ -3872,7 +3823,7 @@
     uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();
 
     if (!mActive && frames != 0) {
-        start();
+        start(0);
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
             MixerThread *mixerThread = (MixerThread *)thread.get();
@@ -4049,6 +4000,7 @@
 AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
     :   RefBase(),
         mAudioFlinger(audioFlinger),
+        // FIXME should be a "k" constant not hard-coded, in .h or ro. property, see 4 lines below
         mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")),
         mPid(pid)
 {
@@ -4061,7 +4013,7 @@
     mAudioFlinger->removeClient_l(mPid);
 }
 
-const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+sp<MemoryDealer> AudioFlinger::Client::heap() const
 {
     return mMemoryDealer;
 }
@@ -4071,13 +4023,12 @@
 AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
                                                      const sp<IAudioFlingerClient>& client,
                                                      pid_t pid)
-    : mAudioFlinger(audioFlinger), mPid(pid), mClient(client)
+    : mAudioFlinger(audioFlinger), mPid(pid), mAudioFlingerClient(client)
 {
 }
 
 AudioFlinger::NotificationClient::~NotificationClient()
 {
-    mClient.clear();
 }
 
 void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who)
@@ -4104,8 +4055,12 @@
     mTrack->destroy();
 }
 
-status_t AudioFlinger::TrackHandle::start() {
-    return mTrack->start();
+sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
+    return mTrack->getCblk();
+}
+
+status_t AudioFlinger::TrackHandle::start(pid_t tid) {
+    return mTrack->start(tid);
 }
 
 void AudioFlinger::TrackHandle::stop() {
@@ -4124,10 +4079,6 @@
     mTrack->pause();
 }
 
-sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
-    return mTrack->getCblk();
-}
-
 status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId)
 {
     return mTrack->attachAuxEffect(EffectId);
@@ -4143,7 +4094,7 @@
 
 sp<IAudioRecord> AudioFlinger::openRecord(
         pid_t pid,
-        int input,
+        audio_io_handle_t input,
         uint32_t sampleRate,
         audio_format_t format,
         uint32_t channelMask,
@@ -4155,7 +4106,6 @@
     sp<RecordThread::RecordTrack> recordTrack;
     sp<RecordHandle> recordHandle;
     sp<Client> client;
-    wp<Client> wclient;
     status_t lStatus;
     RecordThread *thread;
     size_t inFrameCount;
@@ -4176,13 +4126,7 @@
             goto Exit;
         }
 
-        wclient = mClients.valueFor(pid);
-        if (wclient != NULL) {
-            client = wclient.promote();
-        } else {
-            client = new Client(this, pid);
-            mClients.add(pid, client);
-        }
+        client = registerPid_l(pid);
 
         // If no audio session id is provided, create one here
         if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
@@ -4234,9 +4178,13 @@
     stop();
 }
 
-status_t AudioFlinger::RecordHandle::start() {
+sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
+    return mRecordTrack->getCblk();
+}
+
+status_t AudioFlinger::RecordHandle::start(pid_t tid) {
     ALOGV("RecordHandle::start()");
-    return mRecordTrack->start();
+    return mRecordTrack->start(tid);
 }
 
 void AudioFlinger::RecordHandle::stop() {
@@ -4244,10 +4192,6 @@
     mRecordTrack->stop();
 }
 
-sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
-    return mRecordTrack->getCblk();
-}
-
 status_t AudioFlinger::RecordHandle::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -4260,17 +4204,18 @@
                                          AudioStreamIn *input,
                                          uint32_t sampleRate,
                                          uint32_t channels,
-                                         int id,
+                                         audio_io_handle_t id,
                                          uint32_t device) :
-    ThreadBase(audioFlinger, id, device),
-    mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL)
+    ThreadBase(audioFlinger, id, device, RECORD),
+    mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
+    // mRsmpInIndex and mInputBytes set by readInputParameters()
+    mReqChannelCount(popcount(channels)),
+    mReqSampleRate(sampleRate)
+    // mBytesRead is only meaningful while active, and so is cleared in start()
+    // (but might be better to also clear here for dump?)
 {
-    mType = ThreadBase::RECORD;
-
     snprintf(mName, kNameLength, "AudioIn_%d", id);
 
-    mReqChannelCount = popcount(channels);
-    mReqSampleRate = sampleRate;
     readInputParameters();
 }
 
@@ -4278,10 +4223,8 @@
 AudioFlinger::RecordThread::~RecordThread()
 {
     delete[] mRsmpInBuffer;
-    if (mResampler != NULL) {
-        delete mResampler;
-        delete[] mRsmpOutBuffer;
-    }
+    delete mResampler;
+    delete[] mRsmpOutBuffer;
 }
 
 void AudioFlinger::RecordThread::onFirstRef()
@@ -4512,7 +4455,7 @@
         track = new RecordTrack(this, client, sampleRate,
                       format, channelMask, frameCount, flags, sessionId);
 
-        if (track->getCblk() == NULL) {
+        if (track->getCblk() == 0) {
             lStatus = NO_MEMORY;
             goto Exit;
         }
@@ -4533,9 +4476,9 @@
     return track;
 }
 
-status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
+status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack, pid_t tid)
 {
-    ALOGV("RecordThread::start");
+    ALOGV("RecordThread::start tid=%d", tid);
     sp <ThreadBase> strongMe = this;
     status_t status = NO_ERROR;
     {
@@ -4568,7 +4511,7 @@
         ALOGV("Signal record thread");
         mWaitWorkCV.signal();
         // do not wait for mStartStopCond if exiting
-        if (mExiting) {
+        if (exitPending()) {
             mActiveTrack.clear();
             status = INVALID_OPERATION;
             goto startError;
@@ -4595,7 +4538,7 @@
         if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
             mActiveTrack->mState = TrackBase::PAUSING;
             // do not wait for mStartStopCond if exiting
-            if (mExiting) {
+            if (exitPending()) {
                 return;
             }
             mStartStopCond.wait(mLock);
@@ -4615,7 +4558,6 @@
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-    pid_t pid = 0;
 
     snprintf(buffer, SIZE, "\nInput thread %p internals\n", this);
     result.append(buffer);
@@ -4720,7 +4662,7 @@
         }
         if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
             // do not accept frame count changes if tracks are open as the track buffer
-            // size depends on frame count and correct behavior would not be garantied
+            // size depends on frame count and correct behavior would not be guaranteed
             // if frame count is changed after track creation
             if (mActiveTrack != 0) {
                 status = INVALID_OPERATION;
@@ -4803,7 +4745,7 @@
 
 void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param) {
     AudioSystem::OutputDescriptor desc;
-    void *param2 = 0;
+    void *param2 = NULL;
 
     switch (event) {
     case AudioSystem::INPUT_OPENED:
@@ -4825,9 +4767,11 @@
 
 void AudioFlinger::RecordThread::readInputParameters()
 {
-    if (mRsmpInBuffer) delete mRsmpInBuffer;
-    if (mRsmpOutBuffer) delete mRsmpOutBuffer;
-    if (mResampler) delete mResampler;
+    delete mRsmpInBuffer;
+    // mRsmpInBuffer is always assigned a new[] below
+    delete mRsmpOutBuffer;
+    mRsmpOutBuffer = NULL;
+    delete mResampler;
     mResampler = NULL;
 
     mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
@@ -4894,7 +4838,7 @@
     return mTrack;
 }
 
-AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput()
+AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput() const
 {
     Mutex::Autolock _l(mLock);
     return mInput;
@@ -4920,7 +4864,7 @@
 
 // ----------------------------------------------------------------------------
 
-int AudioFlinger::openOutput(uint32_t *pDevices,
+audio_io_handle_t AudioFlinger::openOutput(uint32_t *pDevices,
                                 uint32_t *pSamplingRate,
                                 audio_format_t *pFormat,
                                 uint32_t *pChannels,
@@ -4966,7 +4910,7 @@
     mHardwareStatus = AUDIO_HW_IDLE;
     if (outStream != NULL) {
         AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream);
-        int id = nextUniqueId();
+        audio_io_handle_t id = nextUniqueId();
 
         if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||
             (format != AUDIO_FORMAT_PCM_16_BIT) ||
@@ -4979,10 +4923,10 @@
         }
         mPlaybackThreads.add(id, thread);
 
-        if (pSamplingRate) *pSamplingRate = samplingRate;
-        if (pFormat) *pFormat = format;
-        if (pChannels) *pChannels = channels;
-        if (pLatencyMs) *pLatencyMs = thread->latency();
+        if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
+        if (pFormat != NULL) *pFormat = format;
+        if (pChannels != NULL) *pChannels = channels;
+        if (pLatencyMs != NULL) *pLatencyMs = thread->latency();
 
         // notify client processes of the new output creation
         thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
@@ -4992,7 +4936,8 @@
     return 0;
 }
 
-int AudioFlinger::openDuplicateOutput(int output1, int output2)
+audio_io_handle_t AudioFlinger::openDuplicateOutput(audio_io_handle_t output1,
+        audio_io_handle_t output2)
 {
     Mutex::Autolock _l(mLock);
     MixerThread *thread1 = checkMixerThread_l(output1);
@@ -5003,7 +4948,7 @@
         return 0;
     }
 
-    int id = nextUniqueId();
+    audio_io_handle_t id = nextUniqueId();
     DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);
     thread->addOutputTrack(thread2);
     mPlaybackThreads.add(id, thread);
@@ -5012,7 +4957,7 @@
     return id;
 }
 
-status_t AudioFlinger::closeOutput(int output)
+status_t AudioFlinger::closeOutput(audio_io_handle_t output)
 {
     // keep strong reference on the playback thread so that
     // it is not destroyed while exit() is executed
@@ -5034,14 +4979,17 @@
                 }
             }
         }
-        void *param2 = 0;
+        void *param2 = NULL;
         audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, param2);
         mPlaybackThreads.removeItem(output);
     }
     thread->exit();
+    // The thread entity (active unit of execution) is no longer running here,
+    // but the ThreadBase container still exists.
 
     if (thread->type() != ThreadBase::DUPLICATING) {
         AudioStreamOut *out = thread->clearOutput();
+        assert(out != NULL);
         // from now on thread->mOutput is NULL
         out->hwDev->close_output_stream(out->hwDev, out->stream);
         delete out;
@@ -5049,7 +4997,7 @@
     return NO_ERROR;
 }
 
-status_t AudioFlinger::suspendOutput(int output)
+status_t AudioFlinger::suspendOutput(audio_io_handle_t output)
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -5064,7 +5012,7 @@
     return NO_ERROR;
 }
 
-status_t AudioFlinger::restoreOutput(int output)
+status_t AudioFlinger::restoreOutput(audio_io_handle_t output)
 {
     Mutex::Autolock _l(mLock);
     PlaybackThread *thread = checkPlaybackThread_l(output);
@@ -5080,11 +5028,11 @@
     return NO_ERROR;
 }
 
-int AudioFlinger::openInput(uint32_t *pDevices,
+audio_io_handle_t AudioFlinger::openInput(uint32_t *pDevices,
                                 uint32_t *pSamplingRate,
                                 audio_format_t *pFormat,
                                 uint32_t *pChannels,
-                                uint32_t acoustics)
+                                audio_in_acoustics_t acoustics)
 {
     status_t status;
     RecordThread *thread = NULL;
@@ -5109,7 +5057,7 @@
 
     status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
                                         &channels, &samplingRate,
-                                        (audio_in_acoustics_t)acoustics,
+                                        acoustics,
                                         &inStream);
     ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d",
             inStream,
@@ -5129,14 +5077,14 @@
         ALOGV("openInput() reopening with proposed sampling rate and channels");
         status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
                                             &channels, &samplingRate,
-                                            (audio_in_acoustics_t)acoustics,
+                                            acoustics,
                                             &inStream);
     }
 
     if (inStream != NULL) {
         AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream);
 
-        int id = nextUniqueId();
+        audio_io_handle_t id = nextUniqueId();
         // Start record thread
         // RecorThread require both input and output device indication to forward to audio
         // pre processing modules
@@ -5149,9 +5097,9 @@
                                   device);
         mRecordThreads.add(id, thread);
         ALOGV("openInput() created record thread: ID %d thread %p", id, thread);
-        if (pSamplingRate) *pSamplingRate = reqSamplingRate;
-        if (pFormat) *pFormat = format;
-        if (pChannels) *pChannels = reqChannels;
+        if (pSamplingRate != NULL) *pSamplingRate = reqSamplingRate;
+        if (pFormat != NULL) *pFormat = format;
+        if (pChannels != NULL) *pChannels = reqChannels;
 
         input->stream->common.standby(&input->stream->common);
 
@@ -5163,7 +5111,7 @@
     return 0;
 }
 
-status_t AudioFlinger::closeInput(int input)
+status_t AudioFlinger::closeInput(audio_io_handle_t input)
 {
     // keep strong reference on the record thread so that
     // it is not destroyed while exit() is executed
@@ -5176,13 +5124,16 @@
         }
 
         ALOGV("closeInput() %d", input);
-        void *param2 = 0;
+        void *param2 = NULL;
         audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, param2);
         mRecordThreads.removeItem(input);
     }
     thread->exit();
+    // The thread entity (active unit of execution) is no longer running here,
+    // but the ThreadBase container still exists.
 
     AudioStreamIn *in = thread->clearInput();
+    assert(in != NULL);
     // from now on thread->mInput is NULL
     in->hwDev->close_input_stream(in->hwDev, in->stream);
     delete in;
@@ -5190,7 +5141,7 @@
     return NO_ERROR;
 }
 
-status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, int output)
+status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
 {
     Mutex::Autolock _l(mLock);
     MixerThread *dstThread = checkMixerThread_l(output);
@@ -5226,10 +5177,10 @@
 void AudioFlinger::acquireAudioSessionId(int audioSession)
 {
     Mutex::Autolock _l(mLock);
-    int caller = IPCThreadState::self()->getCallingPid();
+    pid_t caller = IPCThreadState::self()->getCallingPid();
     ALOGV("acquiring %d from %d", audioSession, caller);
-    int num = mAudioSessionRefs.size();
-    for (int i = 0; i< num; i++) {
+    size_t num = mAudioSessionRefs.size();
+    for (size_t i = 0; i< num; i++) {
         AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i);
         if (ref->sessionid == audioSession && ref->pid == caller) {
             ref->cnt++;
@@ -5237,21 +5188,17 @@
             return;
         }
     }
-    AudioSessionRef *ref = new AudioSessionRef();
-    ref->sessionid = audioSession;
-    ref->pid = caller;
-    ref->cnt = 1;
-    mAudioSessionRefs.push(ref);
-    ALOGV(" added new entry for %d", ref->sessionid);
+    mAudioSessionRefs.push(new AudioSessionRef(audioSession, caller));
+    ALOGV(" added new entry for %d", audioSession);
 }
 
 void AudioFlinger::releaseAudioSessionId(int audioSession)
 {
     Mutex::Autolock _l(mLock);
-    int caller = IPCThreadState::self()->getCallingPid();
+    pid_t caller = IPCThreadState::self()->getCallingPid();
     ALOGV("releasing %d from %d", audioSession, caller);
-    int num = mAudioSessionRefs.size();
-    for (int i = 0; i< num; i++) {
+    size_t num = mAudioSessionRefs.size();
+    for (size_t i = 0; i< num; i++) {
         AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
         if (ref->sessionid == audioSession && ref->pid == caller) {
             ref->cnt--;
@@ -5332,7 +5279,7 @@
 }
 
 // checkPlaybackThread_l() must be called with AudioFlinger::mLock held
-AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const
+AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(audio_io_handle_t output) const
 {
     PlaybackThread *thread = NULL;
     if (mPlaybackThreads.indexOfKey(output) >= 0) {
@@ -5342,7 +5289,7 @@
 }
 
 // checkMixerThread_l() must be called with AudioFlinger::mLock held
-AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int output) const
+AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(audio_io_handle_t output) const
 {
     PlaybackThread *thread = checkPlaybackThread_l(output);
     if (thread != NULL) {
@@ -5354,7 +5301,7 @@
 }
 
 // checkRecordThread_l() must be called with AudioFlinger::mLock held
-AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const
+AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(audio_io_handle_t input) const
 {
     RecordThread *thread = NULL;
     if (mRecordThreads.indexOfKey(input) >= 0) {
@@ -5397,19 +5344,20 @@
 // ----------------------------------------------------------------------------
 
 
-status_t AudioFlinger::queryNumberEffects(uint32_t *numEffects)
+status_t AudioFlinger::queryNumberEffects(uint32_t *numEffects) const
 {
     Mutex::Autolock _l(mLock);
     return EffectQueryNumberEffects(numEffects);
 }
 
-status_t AudioFlinger::queryEffect(uint32_t index, effect_descriptor_t *descriptor)
+status_t AudioFlinger::queryEffect(uint32_t index, effect_descriptor_t *descriptor) const
 {
     Mutex::Autolock _l(mLock);
     return EffectQueryEffect(index, descriptor);
 }
 
-status_t AudioFlinger::getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor)
+status_t AudioFlinger::getEffectDescriptor(const effect_uuid_t *pUuid,
+        effect_descriptor_t *descriptor) const
 {
     Mutex::Autolock _l(mLock);
     return EffectGetDescriptor(pUuid, descriptor);
@@ -5420,7 +5368,7 @@
         effect_descriptor_t *pDesc,
         const sp<IEffectClient>& effectClient,
         int32_t priority,
-        int io,
+        audio_io_handle_t io,
         int sessionId,
         status_t *status,
         int *id,
@@ -5429,10 +5377,8 @@
     status_t lStatus = NO_ERROR;
     sp<EffectHandle> handle;
     effect_descriptor_t desc;
-    sp<Client> client;
-    wp<Client> wclient;
 
-    ALOGV("createEffect pid %d, client %p, priority %d, sessionId %d, io %d",
+    ALOGV("createEffect pid %d, effectClient %p, priority %d, sessionId %d, io %d",
             pid, effectClient.get(), priority, sessionId, io);
 
     if (pDesc == NULL) {
@@ -5448,7 +5394,7 @@
 
     // Session AUDIO_SESSION_OUTPUT_STAGE is reserved for output stage effects
     // that can only be created by audio policy manager (running in same process)
-    if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && getpid() != pid) {
+    if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && getpid_cached != pid) {
         lStatus = PERMISSION_DENIED;
         goto Exit;
     }
@@ -5583,14 +5529,7 @@
             }
         }
 
-        wclient = mClients.valueFor(pid);
-
-        if (wclient != NULL) {
-            client = wclient.promote();
-        } else {
-            client = new Client(this, pid);
-            mClients.add(pid, client);
-        }
+        sp<Client> client = registerPid_l(pid);
 
         // create effect on selected output thread
         handle = thread->createEffect_l(client, effectClient, priority, sessionId,
@@ -5607,7 +5546,8 @@
     return handle;
 }
 
-status_t AudioFlinger::moveEffects(int sessionId, int srcOutput, int dstOutput)
+status_t AudioFlinger::moveEffects(int sessionId, audio_io_handle_t srcOutput,
+        audio_io_handle_t dstOutput)
 {
     ALOGV("moveEffects() session %d, srcOutput %d, dstOutput %d",
             sessionId, srcOutput, dstOutput);
@@ -5658,7 +5598,7 @@
 
     // transfer all effects one by one so that new effect chain is created on new thread with
     // correct buffer sizes and audio parameters and effect engines reconfigured accordingly
-    int dstOutput = dstThread->id();
+    audio_io_handle_t dstOutput = dstThread->id();
     sp<EffectChain> dstChain;
     uint32_t strategy = 0; // prevent compiler warning
     sp<EffectModule> effect = chain->getEffectFromId_l(0);
@@ -5786,7 +5726,7 @@
         // create effect handle and connect it to effect module
         handle = new EffectHandle(effect, client, effectClient, priority);
         lStatus = effect->addHandle(handle);
-        if (enabled) {
+        if (enabled != NULL) {
             *enabled = (int)effect->isEnabled();
         }
     }
@@ -5814,13 +5754,8 @@
 
 sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect_l(int sessionId, int effectId)
 {
-    sp<EffectModule> effect;
-
     sp<EffectChain> chain = getEffectChain_l(sessionId);
-    if (chain != 0) {
-        effect = chain->getEffectFromId_l(effectId);
-    }
-    return effect;
+    return chain != 0 ? chain->getEffectFromId_l(effectId) : 0;
 }
 
 // PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
@@ -5905,16 +5840,13 @@
 
 sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain_l(int sessionId)
 {
-    sp<EffectChain> chain;
-
     size_t size = mEffectChains.size();
     for (size_t i = 0; i < size; i++) {
         if (mEffectChains[i]->sessionId() == sessionId) {
-            chain = mEffectChains[i];
-            break;
+            return mEffectChains[i];
         }
     }
-    return chain;
+    return 0;
 }
 
 void AudioFlinger::ThreadBase::setMode(audio_mode_t mode)
@@ -5928,13 +5860,13 @@
 
 void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
                                                     const wp<EffectHandle>& handle,
-                                                    bool unpiniflast) {
+                                                    bool unpinIfLast) {
 
     Mutex::Autolock _l(mLock);
     ALOGV("disconnectEffect() %p effect %p", this, effect.get());
     // delete the effect module if removing last handle on it
     if (effect->removeHandle(handle) == 0) {
-        if (!effect->isPinned() || unpiniflast) {
+        if (!effect->isPinned() || unpinIfLast) {
             removeEffect_l(effect);
             AudioSystem::unregisterEffect(effect->id());
         }
@@ -6173,12 +6105,11 @@
     }
 }
 
-status_t AudioFlinger::EffectModule::addHandle(sp<EffectHandle>& handle)
+status_t AudioFlinger::EffectModule::addHandle(const sp<EffectHandle>& handle)
 {
     status_t status;
 
     Mutex::Autolock _l(mLock);
-    // First handle in mHandles has highest priority and controls the effect module
     int priority = handle->priority();
     size_t size = mHandles.size();
     sp<EffectHandle> h;
@@ -6220,7 +6151,7 @@
 
     bool enabled = false;
     EffectHandle *hdl = handle.unsafe_get();
-    if (hdl) {
+    if (hdl != NULL) {
         ALOGV("removeHandle() unsafe_get OK");
         enabled = hdl->enabled();
     }
@@ -6247,23 +6178,19 @@
 sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle()
 {
     Mutex::Autolock _l(mLock);
-    sp<EffectHandle> handle;
-    if (mHandles.size() != 0) {
-        handle = mHandles[0].promote();
-    }
-    return handle;
+    return mHandles.size() != 0 ? mHandles[0].promote() : 0;
 }
 
-void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpiniflast)
+void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpinIfLast)
 {
-    ALOGV("disconnect() %p handle %p ", this, handle.unsafe_get());
+    ALOGV("disconnect() %p handle %p", this, handle.unsafe_get());
     // keep a strong reference on this EffectModule to avoid calling the
     // destructor before we exit
     sp<EffectModule> keep(this);
     {
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
-            thread->disconnectEffect(keep, handle, unpiniflast);
+            thread->disconnectEffect(keep, handle, unpinIfLast);
         }
     }
 }
@@ -6606,7 +6533,7 @@
     return NO_ERROR;
 }
 
-bool AudioFlinger::EffectModule::isEnabled()
+bool AudioFlinger::EffectModule::isEnabled() const
 {
     switch (mState) {
     case RESTART:
@@ -6622,7 +6549,7 @@
     }
 }
 
-bool AudioFlinger::EffectModule::isProcessEnabled()
+bool AudioFlinger::EffectModule::isProcessEnabled() const
 {
     switch (mState) {
     case RESTART:
@@ -6856,7 +6783,7 @@
     if (mCblkMemory != 0) {
         mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->pointer());
 
-        if (mCblk) {
+        if (mCblk != NULL) {
             new(mCblk) effect_param_cblk_t();
             mBuffer = (uint8_t *)mCblk + bufOffset;
          }
@@ -6935,13 +6862,13 @@
     disconnect(true);
 }
 
-void AudioFlinger::EffectHandle::disconnect(bool unpiniflast)
+void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast)
 {
-    ALOGV("disconnect(%s)", unpiniflast ? "true" : "false");
+    ALOGV("disconnect(%s)", unpinIfLast ? "true" : "false");
     if (mEffect == 0) {
         return;
     }
-    mEffect->disconnect(this, unpiniflast);
+    mEffect->disconnect(this, unpinIfLast);
 
     if (mHasControl && mEnabled) {
         sp<ThreadBase> thread = mEffect->thread().promote();
@@ -6953,10 +6880,12 @@
     // release sp on module => module destructor can be called now
     mEffect.clear();
     if (mClient != 0) {
-        if (mCblk) {
+        if (mCblk != NULL) {
+            // unlike ~TrackBase(), mCblk is never a local new, so don't delete
             mCblk->~effect_param_cblk_t();   // destroy our shared-structure.
         }
-        mCblkMemory.clear();            // and free the shared memory
+        mCblkMemory.clear();    // free the shared memory before releasing the heap it belongs to
+        // Client destructor must run with AudioFlinger mutex locked
         Mutex::Autolock _l(mClient->audioFlinger()->mLock);
         mClient.clear();
     }
@@ -7038,10 +6967,6 @@
     return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
 }
 
-sp<IMemory> AudioFlinger::EffectHandle::getCblk() const {
-    return mCblkMemory;
-}
-
 void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal, bool enabled)
 {
     ALOGV("setControl %p control %d", this, hasControl);
@@ -7083,10 +7008,10 @@
 
 void AudioFlinger::EffectHandle::dump(char* buffer, size_t size)
 {
-    bool locked = mCblk ? tryLock(mCblk->lock) : false;
+    bool locked = mCblk != NULL && tryLock(mCblk->lock);
 
     snprintf(buffer, size, "\t\t\t%05d %05d    %01u    %01u      %05u  %05u\n",
-            (mClient == NULL) ? getpid() : mClient->pid(),
+            (mClient == 0) ? getpid_cached : mClient->pid(),
             mPriority,
             mHasControl,
             !locked,
@@ -7128,48 +7053,42 @@
 // getEffectFromDesc_l() must be called with ThreadBase::mLock held
 sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc_l(effect_descriptor_t *descriptor)
 {
-    sp<EffectModule> effect;
     size_t size = mEffects.size();
 
     for (size_t i = 0; i < size; i++) {
         if (memcmp(&mEffects[i]->desc().uuid, &descriptor->uuid, sizeof(effect_uuid_t)) == 0) {
-            effect = mEffects[i];
-            break;
+            return mEffects[i];
         }
     }
-    return effect;
+    return 0;
 }
 
 // getEffectFromId_l() must be called with ThreadBase::mLock held
 sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int id)
 {
-    sp<EffectModule> effect;
     size_t size = mEffects.size();
 
     for (size_t i = 0; i < size; i++) {
         // by convention, return first effect if id provided is 0 (0 is never a valid id)
         if (id == 0 || mEffects[i]->id() == id) {
-            effect = mEffects[i];
-            break;
+            return mEffects[i];
         }
     }
-    return effect;
+    return 0;
 }
 
 // getEffectFromType_l() must be called with ThreadBase::mLock held
 sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromType_l(
         const effect_uuid_t *type)
 {
-    sp<EffectModule> effect;
     size_t size = mEffects.size();
 
     for (size_t i = 0; i < size; i++) {
         if (memcmp(&mEffects[i]->desc().type, type, sizeof(effect_uuid_t)) == 0) {
-            effect = mEffects[i];
-            break;
+            return mEffects[i];
         }
     }
-    return effect;
+    return 0;
 }
 
 // Must be called with EffectChain::mLock locked
@@ -7260,12 +7179,12 @@
         // Reject insertion if an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is
         // already present
 
-        int size = (int)mEffects.size();
-        int idx_insert = size;
-        int idx_insert_first = -1;
-        int idx_insert_last = -1;
+        size_t size = mEffects.size();
+        size_t idx_insert = size;
+        ssize_t idx_insert_first = -1;
+        ssize_t idx_insert_last = -1;
 
-        for (int i = 0; i < size; i++) {
+        for (size_t i = 0; i < size; i++) {
             effect_descriptor_t d = mEffects[i]->desc();
             uint32_t iMode = d.flags & EFFECT_FLAG_TYPE_MASK;
             uint32_t iPref = d.flags & EFFECT_FLAG_INSERT_MASK;
@@ -7334,11 +7253,10 @@
 size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect)
 {
     Mutex::Autolock _l(mLock);
-    int size = (int)mEffects.size();
-    int i;
+    size_t size = mEffects.size();
     uint32_t type = effect->desc().flags & EFFECT_FLAG_TYPE_MASK;
 
-    for (i = 0; i < size; i++) {
+    for (size_t i = 0; i < size; i++) {
         if (effect == mEffects[i]) {
             // calling stop here will remove pre-processing effect from the audio HAL.
             // This is safe as we hold the EffectChain mutex which guarantees that we are not in
@@ -7485,7 +7403,7 @@
     sp<SuspendedEffectDesc> desc;
     // use effect type UUID timelow as key as there is no real risk of identical
     // timeLow fields among effect type UUIDs.
-    int index = mSuspendedEffects.indexOfKey(type->timeLow);
+    ssize_t index = mSuspendedEffects.indexOfKey(type->timeLow);
     if (suspend) {
         if (index >= 0) {
             desc = mSuspendedEffects.valueAt(index);
@@ -7535,7 +7453,7 @@
 {
     sp<SuspendedEffectDesc> desc;
 
-    int index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
+    ssize_t index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
     if (suspend) {
         if (index >= 0) {
             desc = mSuspendedEffects.valueAt(index);
@@ -7545,7 +7463,8 @@
             ALOGV("setEffectSuspendedAll_l() add entry for 0");
         }
         if (desc->mRefCount++ == 0) {
-            Vector< sp<EffectModule> > effects = getSuspendEligibleEffects();
+            Vector< sp<EffectModule> > effects;
+            getSuspendEligibleEffects(effects);
             for (size_t i = 0; i < effects.size(); i++) {
                 setEffectSuspended_l(&effects[i]->desc().type, true);
             }
@@ -7596,33 +7515,27 @@
     return true;
 }
 
-Vector< sp<AudioFlinger::EffectModule> > AudioFlinger::EffectChain::getSuspendEligibleEffects()
+void AudioFlinger::EffectChain::getSuspendEligibleEffects(Vector< sp<AudioFlinger::EffectModule> > &effects)
 {
-    Vector< sp<EffectModule> > effects;
+    effects.clear();
     for (size_t i = 0; i < mEffects.size(); i++) {
-        if (!isEffectEligibleForSuspend(mEffects[i]->desc())) {
-            continue;
+        if (isEffectEligibleForSuspend(mEffects[i]->desc())) {
+            effects.add(mEffects[i]);
         }
-        effects.add(mEffects[i]);
     }
-    return effects;
 }
 
 sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectIfEnabled(
                                                             const effect_uuid_t *type)
 {
-    sp<EffectModule> effect;
-    effect = getEffectFromType_l(type);
-    if (effect != 0 && !effect->isEnabled()) {
-        effect.clear();
-    }
-    return effect;
+    sp<EffectModule> effect = getEffectFromType_l(type);
+    return effect != 0 && effect->isEnabled() ? effect : 0;
 }
 
 void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
                                                             bool enabled)
 {
-    int index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
+    ssize_t index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
     if (enabled) {
         if (index < 0) {
             // if the effect is not suspend check if all effects are suspended
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 48edfcd..aa0b8f8 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioFlinger.h
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
@@ -67,7 +67,7 @@
 
     virtual     status_t    dump(int fd, const Vector<String16>& args);
 
-    // IAudioFlinger interface
+    // IAudioFlinger interface, in binder opcode order
     virtual sp<IAudioTrack> createTrack(
                                 pid_t pid,
                                 audio_stream_type_t streamType,
@@ -77,117 +77,13 @@
                                 int frameCount,
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
-                                int output,
+                                audio_io_handle_t output,
                                 int *sessionId,
                                 status_t *status);
 
-    virtual     uint32_t    sampleRate(int output) const;
-    virtual     int         channelCount(int output) const;
-    virtual     audio_format_t format(int output) const;
-    virtual     size_t      frameCount(int output) const;
-    virtual     uint32_t    latency(int output) const;
-
-    virtual     status_t    setMasterVolume(float value);
-    virtual     status_t    setMasterMute(bool muted);
-
-    virtual     float       masterVolume() const;
-    virtual     bool        masterMute() const;
-
-    virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value, int output);
-    virtual     status_t    setStreamMute(audio_stream_type_t stream, bool muted);
-
-    virtual     float       streamVolume(audio_stream_type_t stream, int output) const;
-    virtual     bool        streamMute(audio_stream_type_t stream) const;
-
-    virtual     status_t    setMode(audio_mode_t mode);
-
-    virtual     status_t    setMicMute(bool state);
-    virtual     bool        getMicMute() const;
-
-    virtual     status_t    setParameters(int ioHandle, const String8& keyValuePairs);
-    virtual     String8     getParameters(int ioHandle, const String8& keys);
-
-    virtual     void        registerClient(const sp<IAudioFlingerClient>& client);
-
-    virtual     size_t      getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount);
-    virtual     unsigned int  getInputFramesLost(int ioHandle);
-
-    virtual int openOutput(uint32_t *pDevices,
-                                    uint32_t *pSamplingRate,
-                                    audio_format_t *pFormat,
-                                    uint32_t *pChannels,
-                                    uint32_t *pLatencyMs,
-                                    uint32_t flags);
-
-    virtual int openDuplicateOutput(int output1, int output2);
-
-    virtual status_t closeOutput(int output);
-
-    virtual status_t suspendOutput(int output);
-
-    virtual status_t restoreOutput(int output);
-
-    virtual int openInput(uint32_t *pDevices,
-                            uint32_t *pSamplingRate,
-                            audio_format_t *pFormat,
-                            uint32_t *pChannels,
-                            uint32_t acoustics);
-
-    virtual status_t closeInput(int input);
-
-    virtual status_t setStreamOutput(audio_stream_type_t stream, int output);
-
-    virtual status_t setVoiceVolume(float volume);
-
-    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output);
-
-    virtual int newAudioSessionId();
-
-    virtual void acquireAudioSessionId(int audioSession);
-
-    virtual void releaseAudioSessionId(int audioSession);
-
-    virtual status_t queryNumberEffects(uint32_t *numEffects);
-
-    virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor);
-
-    virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor);
-
-    virtual sp<IEffect> createEffect(pid_t pid,
-                        effect_descriptor_t *pDesc,
-                        const sp<IEffectClient>& effectClient,
-                        int32_t priority,
-                        int io,
-                        int sessionId,
-                        status_t *status,
-                        int *id,
-                        int *enabled);
-
-    virtual status_t moveEffects(int sessionId, int srcOutput, int dstOutput);
-
-    enum hardware_call_state {
-        AUDIO_HW_IDLE = 0,
-        AUDIO_HW_INIT,
-        AUDIO_HW_OUTPUT_OPEN,
-        AUDIO_HW_OUTPUT_CLOSE,
-        AUDIO_HW_INPUT_OPEN,
-        AUDIO_HW_INPUT_CLOSE,
-        AUDIO_HW_STANDBY,
-        AUDIO_HW_SET_MASTER_VOLUME,
-        AUDIO_HW_GET_ROUTING,
-        AUDIO_HW_SET_ROUTING,
-        AUDIO_HW_GET_MODE,
-        AUDIO_HW_SET_MODE,
-        AUDIO_HW_GET_MIC_MUTE,
-        AUDIO_HW_SET_MIC_MUTE,
-        AUDIO_SET_VOICE_VOLUME,
-        AUDIO_SET_PARAMETER,
-    };
-
-    // record interface
     virtual sp<IAudioRecord> openRecord(
                                 pid_t pid,
-                                int input,
+                                audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 uint32_t channelMask,
@@ -196,22 +92,116 @@
                                 int *sessionId,
                                 status_t *status);
 
+    virtual     uint32_t    sampleRate(audio_io_handle_t output) const;
+    virtual     int         channelCount(audio_io_handle_t output) const;
+    virtual     audio_format_t format(audio_io_handle_t output) const;
+    virtual     size_t      frameCount(audio_io_handle_t output) const;
+    virtual     uint32_t    latency(audio_io_handle_t output) const;
+
+    virtual     status_t    setMasterVolume(float value);
+    virtual     status_t    setMasterMute(bool muted);
+
+    virtual     float       masterVolume() const;
+    virtual     bool        masterMute() const;
+
+    virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value,
+                                            audio_io_handle_t output);
+    virtual     status_t    setStreamMute(audio_stream_type_t stream, bool muted);
+
+    virtual     float       streamVolume(audio_stream_type_t stream,
+                                         audio_io_handle_t output) const;
+    virtual     bool        streamMute(audio_stream_type_t stream) const;
+
+    virtual     status_t    setMode(audio_mode_t mode);
+
+    virtual     status_t    setMicMute(bool state);
+    virtual     bool        getMicMute() const;
+
+    virtual     status_t    setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
+    virtual     String8     getParameters(audio_io_handle_t ioHandle, const String8& keys) const;
+
+    virtual     void        registerClient(const sp<IAudioFlingerClient>& client);
+
+    virtual     size_t      getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const;
+
+    virtual audio_io_handle_t openOutput(uint32_t *pDevices,
+                                    uint32_t *pSamplingRate,
+                                    audio_format_t *pFormat,
+                                    uint32_t *pChannels,
+                                    uint32_t *pLatencyMs,
+                                    uint32_t flags);
+
+    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+                                                  audio_io_handle_t output2);
+
+    virtual status_t closeOutput(audio_io_handle_t output);
+
+    virtual status_t suspendOutput(audio_io_handle_t output);
+
+    virtual status_t restoreOutput(audio_io_handle_t output);
+
+    virtual audio_io_handle_t openInput(uint32_t *pDevices,
+                            uint32_t *pSamplingRate,
+                            audio_format_t *pFormat,
+                            uint32_t *pChannels,
+                            audio_in_acoustics_t acoustics);
+
+    virtual status_t closeInput(audio_io_handle_t input);
+
+    virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output);
+
+    virtual status_t setVoiceVolume(float volume);
+
+    virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
+                                       audio_io_handle_t output) const;
+
+    virtual     unsigned int  getInputFramesLost(audio_io_handle_t ioHandle) const;
+
+    virtual int newAudioSessionId();
+
+    virtual void acquireAudioSessionId(int audioSession);
+
+    virtual void releaseAudioSessionId(int audioSession);
+
+    virtual status_t queryNumberEffects(uint32_t *numEffects) const;
+
+    virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor) const;
+
+    virtual status_t getEffectDescriptor(const effect_uuid_t *pUuid,
+                                         effect_descriptor_t *descriptor) const;
+
+    virtual sp<IEffect> createEffect(pid_t pid,
+                        effect_descriptor_t *pDesc,
+                        const sp<IEffectClient>& effectClient,
+                        int32_t priority,
+                        audio_io_handle_t io,
+                        int sessionId,
+                        status_t *status,
+                        int *id,
+                        int *enabled);
+
+    virtual status_t moveEffects(int sessionId, audio_io_handle_t srcOutput,
+                        audio_io_handle_t dstOutput);
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
                                 Parcel* reply,
                                 uint32_t flags);
 
-               audio_mode_t getMode() const { return mMode; }
-
-                bool        btNrecIsOff() { return mBtNrecIsOff; }
+    // end of IAudioFlinger interface
 
 private:
+               audio_mode_t getMode() const { return mMode; }
+
+                bool        btNrecIsOff() const { return mBtNrecIsOff; }
 
                             AudioFlinger();
     virtual                 ~AudioFlinger();
 
-    status_t                initCheck() const;
+    // call in any IAudioFlinger method that accesses mPrimaryHardwareDev
+    status_t                initCheck() const { return mPrimaryHardwareDev == NULL ? NO_INIT : NO_ERROR; }
+
     virtual     void        onFirstRef();
     audio_hw_device_t*      findSuitableHwDev_l(uint32_t devices);
     void                    purgeStaleEffects_l();
@@ -226,16 +216,16 @@
     public:
                             Client(const sp<AudioFlinger>& audioFlinger, pid_t pid);
         virtual             ~Client();
-        const sp<MemoryDealer>&     heap() const;
+        sp<MemoryDealer>    heap() const;
         pid_t               pid() const { return mPid; }
-        sp<AudioFlinger>    audioFlinger() { return mAudioFlinger; }
+        sp<AudioFlinger>    audioFlinger() const { return mAudioFlinger; }
 
     private:
                             Client(const Client&);
                             Client& operator = (const Client&);
-        sp<AudioFlinger>    mAudioFlinger;
-        sp<MemoryDealer>    mMemoryDealer;
-        pid_t               mPid;
+        const sp<AudioFlinger> mAudioFlinger;
+        const sp<MemoryDealer> mMemoryDealer;
+        const pid_t         mPid;
     };
 
     // --- Notification Client ---
@@ -246,7 +236,7 @@
                                                 pid_t pid);
         virtual             ~NotificationClient();
 
-                sp<IAudioFlingerClient>    client() { return mClient; }
+                sp<IAudioFlingerClient> audioFlingerClient() const { return mAudioFlingerClient; }
 
                 // IBinder::DeathRecipient
                 virtual     void        binderDied(const wp<IBinder>& who);
@@ -255,9 +245,9 @@
                             NotificationClient(const NotificationClient&);
                             NotificationClient& operator = (const NotificationClient&);
 
-        sp<AudioFlinger>        mAudioFlinger;
-        pid_t                   mPid;
-        sp<IAudioFlingerClient> mClient;
+        const sp<AudioFlinger>  mAudioFlinger;
+        const pid_t             mPid;
+        const sp<IAudioFlingerClient> mAudioFlingerClient;
     };
 
     class TrackHandle;
@@ -277,17 +267,17 @@
 
     class ThreadBase : public Thread {
     public:
-        ThreadBase (const sp<AudioFlinger>& audioFlinger, int id, uint32_t device);
-        virtual             ~ThreadBase();
 
-
-        enum type {
+        enum type_t {
             MIXER,              // Thread class is MixerThread
             DIRECT,             // Thread class is DirectOutputThread
             DUPLICATING,        // Thread class is DuplicatingThread
             RECORD              // Thread class is RecordThread
         };
 
+        ThreadBase (const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, uint32_t device, type_t type);
+        virtual             ~ThreadBase();
+
         status_t dumpBase(int fd, const Vector<String16>& args);
         status_t dumpEffectChains(int fd, const Vector<String16>& args);
 
@@ -300,6 +290,8 @@
             enum track_state {
                 IDLE,
                 TERMINATED,
+                // These are order-sensitive; do not change order without reviewing the impact.
+                // In particular there are assumptions about > STOPPED.
                 STOPPED,
                 RESUMING,
                 ACTIVE,
@@ -322,13 +314,13 @@
                                         uint32_t flags,
                                         const sp<IMemory>& sharedBuffer,
                                         int sessionId);
-                                ~TrackBase();
+            virtual             ~TrackBase();
 
-            virtual status_t    start() = 0;
+            virtual status_t    start(pid_t tid) = 0;
             virtual void        stop() = 0;
-                    sp<IMemory> getCblk() const;
+                    sp<IMemory> getCblk() const { return mCblkMemory; }
                     audio_track_cblk_t* cblk() const { return mCblk; }
-                    int         sessionId() { return mSessionId; }
+                    int         sessionId() const { return mSessionId; }
 
         protected:
             friend class ThreadBase;
@@ -348,11 +340,11 @@
                 return mFormat;
             }
 
-            int channelCount() const ;
+            int channelCount() const { return mChannelCount; }
 
-            uint32_t channelMask() const;
+            uint32_t channelMask() const { return mChannelMask; }
 
-            int sampleRate() const;
+            int sampleRate() const; // FIXME inline after cblk sr moved
 
             void* getBuffer(uint32_t offset, uint32_t frames) const;
 
@@ -367,19 +359,18 @@
             bool step();
             void reset();
 
-            wp<ThreadBase>      mThread;
-            sp<Client>          mClient;
+            const wp<ThreadBase> mThread;
+            /*const*/ sp<Client> mClient;   // see explanation at ~TrackBase() why not const
             sp<IMemory>         mCblkMemory;
             audio_track_cblk_t* mCblk;
             void*               mBuffer;
             void*               mBufferEnd;
             uint32_t            mFrameCount;
             // we don't really need a lock for these
-            int                 mState;
-            int                 mClientTid;
-            audio_format_t      mFormat;
+            track_state         mState;
+            const audio_format_t mFormat;
             uint32_t            mFlags;
-            int                 mSessionId;
+            const int           mSessionId;
             uint8_t             mChannelCount;
             uint32_t            mChannelMask;
         };
@@ -408,12 +399,14 @@
         };
 
         virtual     status_t    initCheck() const = 0;
-                    int         type() const { return mType; }
-                    uint32_t    sampleRate() const;
-                    int         channelCount() const;
-                    audio_format_t format() const;
-                    size_t      frameCount() const;
+                    type_t      type() const { return mType; }
+                    uint32_t    sampleRate() const { return mSampleRate; }
+                    int         channelCount() const { return mChannelCount; }
+                    audio_format_t format() const { return mFormat; }
+                    size_t      frameCount() const { return mFrameCount; }
                     void        wakeUp()    { mWaitWorkCV.broadcast(); }
+        // Should be "virtual status_t requestExitAndWait()" and override same
+        // method in Thread, but Thread::requestExitAndWait() is not yet virtual.
                     void        exit();
         virtual     bool        checkForNewParameters_l() = 0;
         virtual     status_t    setParameters(const String8& keyValuePairs);
@@ -422,7 +415,7 @@
                     void        sendConfigEvent(int event, int param = 0);
                     void        sendConfigEvent_l(int event, int param = 0);
                     void        processConfigEvents();
-                    int         id() const { return mId;}
+                    audio_io_handle_t id() const { return mId;}
                     bool        standby() { return mStandby; }
                     uint32_t    device() { return mDevice; }
         virtual     audio_stream_t* stream() = 0;
@@ -437,7 +430,7 @@
                                         status_t *status);
                     void disconnectEffect(const sp< EffectModule>& effect,
                                           const wp<EffectHandle>& handle,
-                                          bool unpiniflast);
+                                          bool unpinIfLast);
 
                     // return values for hasAudioSession (bit field)
                     enum effect_state {
@@ -530,9 +523,9 @@
         friend class RecordThread;
         friend class RecordTrack;
 
-                    int                     mType;
+                    const type_t            mType;
                     Condition               mWaitWorkCV;
-                    sp<AudioFlinger>        mAudioFlinger;
+                    const sp<AudioFlinger>  mAudioFlinger;
                     uint32_t                mSampleRate;
                     size_t                  mFrameCount;
                     uint32_t                mChannelMask;
@@ -544,8 +537,7 @@
                     status_t                mParamStatus;
                     Vector<ConfigEvent>     mConfigEvents;
                     bool                    mStandby;
-                    int                     mId;
-                    bool                    mExiting;
+                    const audio_io_handle_t mId;
                     Vector< sp<EffectChain> > mEffectChains;
                     uint32_t                mDevice;    // output device for PlaybackThread
                                                         // input + output devices for RecordThread
@@ -553,12 +545,24 @@
                     char                    mName[kNameLength];
                     sp<IPowerManager>       mPowerManager;
                     sp<IBinder>             mWakeLockToken;
-                    sp<PMDeathRecipient>    mDeathRecipient;
+                    const sp<PMDeathRecipient> mDeathRecipient;
                     // list of suspended effects per session and per type. The first vector is
                     // keyed by session ID, the second by type UUID timeLow field
                     KeyedVector< int, KeyedVector< int, sp<SuspendedSessionDesc> > >  mSuspendedSessions;
     };
 
+    struct  stream_type_t {
+        stream_type_t()
+            :   volume(1.0f),
+                mute(false),
+                valid(true)
+        {
+        }
+        float       volume;
+        bool        mute;
+        bool        valid;
+    };
+
     // --- PlaybackThread ---
     class PlaybackThread : public ThreadBase {
     public:
@@ -581,10 +585,10 @@
                                         int frameCount,
                                         const sp<IMemory>& sharedBuffer,
                                         int sessionId);
-                                ~Track();
+            virtual             ~Track();
 
                     void        dump(char* buffer, size_t size);
-            virtual status_t    start();
+            virtual status_t    start(pid_t tid);
             virtual void        stop();
                     void        pause();
 
@@ -595,15 +599,15 @@
                         return mName;
                     }
 
-                    audio_stream_type_t type() const {
+                    audio_stream_type_t streamType() const {
                         return mStreamType;
                     }
                     status_t    attachAuxEffect(int EffectId);
                     void        setAuxBuffer(int EffectId, int32_t *buffer);
-                    int32_t     *auxBuffer() { return mAuxBuffer; }
+                    int32_t     *auxBuffer() const { return mAuxBuffer; }
                     void        setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
-                    int16_t     *mainBuffer() { return mMainBuffer; }
-                    int         auxEffectId() { return mAuxEffectId; }
+                    int16_t     *mainBuffer() const { return mMainBuffer; }
+                    int         auxEffectId() const { return mAuxEffectId; }
 
 
         protected:
@@ -617,7 +621,7 @@
                                 Track& operator = (const Track&);
 
             virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
-            bool isMuted() { return mMute; }
+            bool isMuted() const { return mMute; }
             bool isPausing() const {
                 return mState == PAUSING;
             }
@@ -664,14 +668,14 @@
                                         audio_format_t format,
                                         uint32_t channelMask,
                                         int frameCount);
-                                ~OutputTrack();
+            virtual             ~OutputTrack();
 
-            virtual status_t    start();
+            virtual status_t    start(pid_t tid);
             virtual void        stop();
                     bool        write(int16_t* data, uint32_t frames);
-                    bool        bufferQueueEmpty() { return (mBufferQueue.size() == 0) ? true : false; }
-                    bool        isActive() { return mActive; }
-            wp<ThreadBase>&     thread()  { return mThread; }
+                    bool        bufferQueueEmpty() const { return (mBufferQueue.size() == 0) ? true : false; }
+                    bool        isActive() const { return mActive; }
+            const wp<ThreadBase>& thread() const { return mThread; }
 
         private:
 
@@ -688,10 +692,11 @@
             Vector < Buffer* >          mBufferQueue;
             AudioBufferProvider::Buffer mOutBuffer;
             bool                        mActive;
-            DuplicatingThread*          mSourceThread;
+            DuplicatingThread* const mSourceThread; // for waitTimeMs() in write()
         };  // end of OutputTrack
 
-        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
+        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
+                        audio_io_handle_t id, uint32_t device, type_t type);
         virtual             ~PlaybackThread();
 
         virtual     status_t    dump(int fd, const Vector<String16>& args);
@@ -704,17 +709,13 @@
 
         virtual     uint32_t    latency() const;
 
-        virtual     status_t    setMasterVolume(float value);
-        virtual     status_t    setMasterMute(bool muted);
+                    void        setMasterVolume(float value);
+                    void        setMasterMute(bool muted);
 
-        virtual     float       masterVolume() const;
-        virtual     bool        masterMute() const;
+                    void        setStreamVolume(audio_stream_type_t stream, float value);
+                    void        setStreamMute(audio_stream_type_t stream, bool muted);
 
-        virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value);
-        virtual     status_t    setStreamMute(audio_stream_type_t stream, bool muted);
-
-        virtual     float       streamVolume(audio_stream_type_t stream) const;
-        virtual     bool        streamMute(audio_stream_type_t stream) const;
+                    float       streamVolume(audio_stream_type_t stream) const;
 
                     sp<Track>   createTrack_l(
                                     const sp<AudioFlinger::Client>& client,
@@ -727,7 +728,7 @@
                                     int sessionId,
                                     status_t *status);
 
-                    AudioStreamOut* getOutput();
+                    AudioStreamOut* getOutput() const;
                     AudioStreamOut* clearOutput();
                     virtual audio_stream_t* stream();
 
@@ -737,7 +738,7 @@
         virtual     String8     getParameters(const String8& keys);
         virtual     void        audioConfigChanged_l(int event, int param = 0);
         virtual     status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
-                    int16_t     *mixBuffer() { return mMixBuffer; };
+                    int16_t     *mixBuffer() const { return mMixBuffer; };
 
         virtual     void detachAuxEffect_l(int effectId);
                     status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track,
@@ -752,24 +753,16 @@
 
                             void setStreamValid(audio_stream_type_t streamType, bool valid);
 
-        struct  stream_type_t {
-            stream_type_t()
-                :   volume(1.0f),
-                    mute(false),
-                    valid(true)
-            {
-            }
-            float       volume;
-            bool        mute;
-            bool        valid;
-        };
-
     protected:
         int16_t*                        mMixBuffer;
         int                             mSuspended;
         int                             mBytesWritten;
     private:
+        // mMasterMute is in both PlaybackThread and in AudioFlinger.  When a
+        // PlaybackThread needs to find out if master-muted, it checks it's local
+        // copy rather than the one in AudioFlinger.  This optimization saves a lock.
         bool                            mMasterMute;
+                    void        setMasterMute_l(bool muted) { mMasterMute = muted; }
     protected:
         SortedVector< wp<Track> >       mActiveTracks;
 
@@ -804,7 +797,7 @@
         SortedVector< sp<Track> >       mTracks;
         // mStreamTypes[] uses 1 additional stream type internally for the OutputTrack used by DuplicatingThread
         stream_type_t                   mStreamTypes[AUDIO_STREAM_CNT + 1];
-        AudioStreamOut*                 mOutput;
+        AudioStreamOut                  *mOutput;
         float                           mMasterVolume;
         nsecs_t                         mLastWriteTime;
         int                             mNumWrites;
@@ -816,8 +809,9 @@
     public:
         MixerThread (const sp<AudioFlinger>& audioFlinger,
                      AudioStreamOut* output,
-                     int id,
-                     uint32_t device);
+                     audio_io_handle_t id,
+                     uint32_t device,
+                     type_t type = MIXER);
         virtual             ~MixerThread();
 
         // Thread virtuals
@@ -828,7 +822,7 @@
         virtual     status_t    dumpInternals(int fd, const Vector<String16>& args);
 
     protected:
-                    uint32_t    prepareTracks_l(const SortedVector< wp<Track> >& activeTracks,
+                    mixer_state prepareTracks_l(const SortedVector< wp<Track> >& activeTracks,
                                                 Vector< sp<Track> > *tracksToRemove);
         virtual     int         getTrackName_l();
         virtual     void        deleteTrackName_l(int name);
@@ -836,15 +830,15 @@
         virtual     uint32_t    suspendSleepTimeUs();
 
                     AudioMixer* mAudioMixer;
-                    uint32_t    mPrevMixerStatus; // previous status (mixer_state) returned by
-                                                  // prepareTracks_l()
+                    mixer_state mPrevMixerStatus; // previous status returned by prepareTracks_l()
     };
 
     class DirectOutputThread : public PlaybackThread {
     public:
 
-        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
-        ~DirectOutputThread();
+        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
+                            audio_io_handle_t id, uint32_t device);
+        virtual                 ~DirectOutputThread();
 
         // Thread virtuals
         virtual     bool        threadLoop();
@@ -861,6 +855,8 @@
     private:
         void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp);
 
+        // volumes last sent to audio HAL with stream->set_volume()
+        // FIXME use standard representation and names
         float mLeftVolFloat;
         float mRightVolFloat;
         uint16_t mLeftVolShort;
@@ -869,8 +865,9 @@
 
     class DuplicatingThread : public MixerThread {
     public:
-        DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread, int id);
-        ~DuplicatingThread();
+        DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread,
+                           audio_io_handle_t id);
+        virtual                 ~DuplicatingThread();
 
         // Thread virtuals
         virtual     bool        threadLoop();
@@ -888,13 +885,20 @@
                     uint32_t    mWaitTimeMs;
     };
 
-              PlaybackThread *checkPlaybackThread_l(int output) const;
-              MixerThread *checkMixerThread_l(int output) const;
-              RecordThread *checkRecordThread_l(int input) const;
-              float streamVolumeInternal(audio_stream_type_t stream) const { return mStreamTypes[stream].volume; }
-              void audioConfigChanged_l(int event, int ioHandle, void *param2);
+              PlaybackThread *checkPlaybackThread_l(audio_io_handle_t output) const;
+              MixerThread *checkMixerThread_l(audio_io_handle_t output) const;
+              RecordThread *checkRecordThread_l(audio_io_handle_t input) const;
+              // no range check, AudioFlinger::mLock held
+              bool streamMute_l(audio_stream_type_t stream) const
+                                { return mStreamTypes[stream].mute; }
+              // no range check, doesn't check per-thread stream volume, AudioFlinger::mLock held
+              float streamVolume_l(audio_stream_type_t stream) const
+                                { return mStreamTypes[stream].volume; }
+              void audioConfigChanged_l(int event, audio_io_handle_t ioHandle, void *param2);
 
+              // allocate an audio_io_handle_t, session ID, or effect ID
               uint32_t nextUniqueId();
+
               status_t moveEffectChain_l(int sessionId,
                                      AudioFlinger::PlaybackThread *srcThread,
                                      AudioFlinger::PlaybackThread *dstThread,
@@ -904,21 +908,22 @@
 
     friend class AudioBuffer;
 
+    // server side of the client's IAudioTrack
     class TrackHandle : public android::BnAudioTrack {
     public:
                             TrackHandle(const sp<PlaybackThread::Track>& track);
         virtual             ~TrackHandle();
-        virtual status_t    start();
+        virtual sp<IMemory> getCblk() const;
+        virtual status_t    start(pid_t tid);
         virtual void        stop();
         virtual void        flush();
         virtual void        mute(bool);
         virtual void        pause();
-        virtual sp<IMemory> getCblk() const;
         virtual status_t    attachAuxEffect(int effectId);
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
-        sp<PlaybackThread::Track> mTrack;
+        const sp<PlaybackThread::Track> mTrack;
     };
 
     friend class Client;
@@ -945,9 +950,9 @@
                                         int frameCount,
                                         uint32_t flags,
                                         int sessionId);
-                                ~RecordTrack();
+            virtual             ~RecordTrack();
 
-            virtual status_t    start();
+            virtual status_t    start(pid_t tid);
             virtual void        stop();
 
                     bool        overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
@@ -972,9 +977,9 @@
                         AudioStreamIn *input,
                         uint32_t sampleRate,
                         uint32_t channels,
-                        int id,
+                        audio_io_handle_t id,
                         uint32_t device);
-                ~RecordThread();
+                virtual     ~RecordThread();
 
         virtual bool        threadLoop();
         virtual status_t    readyToRun();
@@ -992,9 +997,10 @@
                         status_t *status);
 
                 status_t    start(RecordTrack* recordTrack);
+                status_t    start(RecordTrack* recordTrack, pid_t tid);
                 void        stop(RecordTrack* recordTrack);
                 status_t    dump(int fd, const Vector<String16>& args);
-                AudioStreamIn* getInput();
+                AudioStreamIn* getInput() const;
                 AudioStreamIn* clearInput();
                 virtual audio_stream_t* stream();
 
@@ -1022,22 +1028,23 @@
                 int16_t                             *mRsmpInBuffer;
                 size_t                              mRsmpInIndex;
                 size_t                              mInputBytes;
-                int                                 mReqChannelCount;
-                uint32_t                            mReqSampleRate;
+                const int                           mReqChannelCount;
+                const uint32_t                      mReqSampleRate;
                 ssize_t                             mBytesRead;
     };
 
+    // server side of the client's IAudioRecord
     class RecordHandle : public android::BnAudioRecord {
     public:
         RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
         virtual             ~RecordHandle();
-        virtual status_t    start();
-        virtual void        stop();
         virtual sp<IMemory> getCblk() const;
+        virtual status_t    start(pid_t tid);
+        virtual void        stop();
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
-        sp<RecordThread::RecordTrack> mRecordTrack;
+        const sp<RecordThread::RecordTrack> mRecordTrack;
     };
 
     //--- Audio Effect Management
@@ -1063,7 +1070,7 @@
                         effect_descriptor_t *desc,
                         int id,
                         int sessionId);
-        ~EffectModule();
+        virtual ~EffectModule();
 
         enum effect_state {
             IDLE,
@@ -1075,7 +1082,7 @@
             DESTROYED
         };
 
-        int         id() { return mId; }
+        int         id() const { return mId; }
         void process();
         void updateState();
         status_t command(uint32_t cmdCode,
@@ -1087,18 +1094,18 @@
         void reset_l();
         status_t configure();
         status_t init();
-        uint32_t state() {
+        effect_state state() const {
             return mState;
         }
         uint32_t status() {
             return mStatus;
         }
-        int sessionId() {
+        int sessionId() const {
             return mSessionId;
         }
         status_t    setEnabled(bool enabled);
-        bool isEnabled();
-        bool isProcessEnabled();
+        bool isEnabled() const;
+        bool isProcessEnabled() const;
 
         void        setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
         int16_t     *inBuffer() { return mConfig.inputCfg.buffer.s16; }
@@ -1106,10 +1113,10 @@
         int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; }
         void        setChain(const wp<EffectChain>& chain) { mChain = chain; }
         void        setThread(const wp<ThreadBase>& thread) { mThread = thread; }
-        wp<ThreadBase>& thread() { return mThread; }
+        const wp<ThreadBase>& thread() { return mThread; }
 
-        status_t addHandle(sp<EffectHandle>& handle);
-        void disconnect(const wp<EffectHandle>& handle, bool unpiniflast);
+        status_t addHandle(const sp<EffectHandle>& handle);
+        void disconnect(const wp<EffectHandle>& handle, bool unpinIfLast);
         size_t removeHandle (const wp<EffectHandle>& handle);
 
         effect_descriptor_t& desc() { return mDescriptor; }
@@ -1125,7 +1132,7 @@
 
         sp<EffectHandle> controlHandle();
 
-        bool             isPinned() { return mPinned; }
+        bool             isPinned() const { return mPinned; }
         void             unPin() { mPinned = false; }
 
         status_t         dump(int fd, const Vector<String16>& args);
@@ -1152,9 +1159,10 @@
         effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
         effect_config_t     mConfig;    // input and output audio configuration
         effect_handle_t  mEffectInterface; // Effect module C API
-        status_t mStatus;               // initialization status
-        uint32_t mState;                // current activation state (effect_state)
+        status_t            mStatus;    // initialization status
+        effect_state        mState;     // current activation state
         Vector< wp<EffectHandle> > mHandles;    // list of client handles
+                    // First handle in mHandles has highest priority and controls the effect module
         uint32_t mMaxDisableWaitCnt;    // maximum grace period before forcing an effect off after
                                         // sending disable command.
         uint32_t mDisableWaitCnt;       // current process() calls count during disable period.
@@ -1185,8 +1193,10 @@
                                  uint32_t *replySize,
                                  void *pReplyData);
         virtual void disconnect();
-        virtual void disconnect(bool unpiniflast);
-        virtual sp<IMemory> getCblk() const;
+    private:
+                void disconnect(bool unpinIfLast);
+    public:
+        virtual sp<IMemory> getCblk() const { return mCblkMemory; }
         virtual status_t onTransact(uint32_t code, const Parcel& data,
                 Parcel* reply, uint32_t flags);
 
@@ -1202,13 +1212,13 @@
                              uint32_t replySize,
                              void *pReplyData);
         void setEnabled(bool enabled);
-        bool enabled() { return mEnabled; }
+        bool enabled() const { return mEnabled; }
 
         // Getters
-        int id() { return mEffect->id(); }
-        int priority() { return mPriority; }
-        bool hasControl() { return mHasControl; }
-        sp<EffectModule> effect() { return mEffect; }
+        int id() const { return mEffect->id(); }
+        int priority() const { return mPriority; }
+        bool hasControl() const { return mHasControl; }
+        sp<EffectModule> effect() const { return mEffect; }
 
         void dump(char* buffer, size_t size);
 
@@ -1220,7 +1230,7 @@
 
         sp<EffectModule> mEffect;           // pointer to controlled EffectModule
         sp<IEffectClient> mEffectClient;    // callback interface for client notifications
-        sp<Client>          mClient;        // client for shared memory allocation
+        /*const*/ sp<Client> mClient;       // client for shared memory allocation, see disconnect()
         sp<IMemory>         mCblkMemory;    // shared memory for control block
         effect_param_cblk_t* mCblk;         // control block for deferred parameter setting via shared memory
         uint8_t*            mBuffer;        // pointer to parameter area in shared memory
@@ -1240,7 +1250,7 @@
     class EffectChain: public RefBase {
     public:
         EffectChain(const wp<ThreadBase>& wThread, int sessionId);
-        ~EffectChain();
+        virtual ~EffectChain();
 
         // special key used for an entry in mSuspendedEffects keyed vector
         // corresponding to a suspend all request.
@@ -1262,7 +1272,7 @@
         status_t addEffect_l(const sp<EffectModule>& handle);
         size_t removeEffect_l(const sp<EffectModule>& handle);
 
-        int sessionId() { return mSessionId; }
+        int sessionId() const { return mSessionId; }
         void setSessionId(int sessionId) { mSessionId = sessionId; }
 
         sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
@@ -1276,26 +1286,26 @@
             mInBuffer = buffer;
             mOwnInBuffer = ownsBuffer;
         }
-        int16_t *inBuffer() {
+        int16_t *inBuffer() const {
             return mInBuffer;
         }
         void setOutBuffer(int16_t *buffer) {
             mOutBuffer = buffer;
         }
-        int16_t *outBuffer() {
+        int16_t *outBuffer() const {
             return mOutBuffer;
         }
 
         void incTrackCnt() { android_atomic_inc(&mTrackCnt); }
         void decTrackCnt() { android_atomic_dec(&mTrackCnt); }
-        int32_t trackCnt() { return mTrackCnt;}
+        int32_t trackCnt() const { return mTrackCnt;}
 
         void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt);
                                    mTailBufferCount = mMaxTailBuffers; }
         void decActiveTrackCnt() { android_atomic_dec(&mActiveTrackCnt); }
-        int32_t activeTrackCnt() { return mActiveTrackCnt;}
+        int32_t activeTrackCnt() const { return mActiveTrackCnt;}
 
-        uint32_t strategy() { return mStrategy; }
+        uint32_t strategy() const { return mStrategy; }
         void setStrategy(uint32_t strategy)
                  { mStrategy = strategy; }
 
@@ -1326,7 +1336,8 @@
 
         // get a list of effect modules to suspend when an effect of the type
         // passed is enabled.
-        Vector< sp<EffectModule> > getSuspendEligibleEffects();
+        void                       getSuspendEligibleEffects(Vector< sp<EffectModule> > &effects);
+
         // get an effect module if it is currently enable
         sp<EffectModule> getEffectIfEnabled(const effect_uuid_t *type);
         // true if the effect whose descriptor is passed can be suspended
@@ -1357,25 +1368,33 @@
         KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
     };
 
+    // AudioStreamOut and AudioStreamIn are immutable, so their fields are const.
+    // For emphasis, we could also make all pointers to them be "const *",
+    // but that would clutter the code unnecessarily.
+
     struct AudioStreamOut {
-        audio_hw_device_t   *hwDev;
-        audio_stream_out_t  *stream;
+        audio_hw_device_t*  const hwDev;
+        audio_stream_out_t* const stream;
 
         AudioStreamOut(audio_hw_device_t *dev, audio_stream_out_t *out) :
             hwDev(dev), stream(out) {}
     };
 
     struct AudioStreamIn {
-        audio_hw_device_t   *hwDev;
-        audio_stream_in_t   *stream;
+        audio_hw_device_t* const hwDev;
+        audio_stream_in_t* const stream;
 
         AudioStreamIn(audio_hw_device_t *dev, audio_stream_in_t *in) :
             hwDev(dev), stream(in) {}
     };
 
+    // for mAudioSessionRefs only
     struct AudioSessionRef {
-        int sessionid;
-        pid_t pid;
+        // FIXME rename parameter names when fields get "m" prefix
+        AudioSessionRef(int sessionid_, pid_t pid_) :
+            sessionid(sessionid_), pid(pid_), cnt(1) {}
+        const int sessionid;
+        const pid_t pid;
         int cnt;
     };
 
@@ -1384,32 +1403,60 @@
 
     mutable     Mutex                               mLock;
 
-                DefaultKeyedVector< pid_t, wp<Client> >     mClients;
+                DefaultKeyedVector< pid_t, wp<Client> >     mClients;   // see ~Client()
 
                 mutable     Mutex                   mHardwareLock;
-                audio_hw_device_t*                  mPrimaryHardwareDev;
+
+                // These two fields are immutable after onFirstRef(), so no lock needed to access
+                audio_hw_device_t*                  mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
                 Vector<audio_hw_device_t*>          mAudioHwDevs;
+
+    enum hardware_call_state {
+        AUDIO_HW_IDLE = 0,
+        AUDIO_HW_INIT,
+        AUDIO_HW_OUTPUT_OPEN,
+        AUDIO_HW_OUTPUT_CLOSE,
+        AUDIO_HW_INPUT_OPEN,
+        AUDIO_HW_INPUT_CLOSE,
+        AUDIO_HW_STANDBY,
+        AUDIO_HW_SET_MASTER_VOLUME,
+        AUDIO_HW_GET_ROUTING,
+        AUDIO_HW_SET_ROUTING,
+        AUDIO_HW_GET_MODE,
+        AUDIO_HW_SET_MODE,
+        AUDIO_HW_GET_MIC_MUTE,
+        AUDIO_HW_SET_MIC_MUTE,
+        AUDIO_SET_VOICE_VOLUME,
+        AUDIO_SET_PARAMETER,
+        AUDIO_HW_GET_INPUT_BUFFER_SIZE,
+    };
+
     mutable     hardware_call_state                 mHardwareStatus;    // for dump only
 
 
-                DefaultKeyedVector< int, sp<PlaybackThread> >  mPlaybackThreads;
-                PlaybackThread::stream_type_t       mStreamTypes[AUDIO_STREAM_CNT];
+                DefaultKeyedVector< audio_io_handle_t, sp<PlaybackThread> >  mPlaybackThreads;
+                stream_type_t                       mStreamTypes[AUDIO_STREAM_CNT];
 
                 // both are protected by mLock
                 float                               mMasterVolume;
                 bool                                mMasterMute;
 
-                DefaultKeyedVector< int, sp<RecordThread> >    mRecordThreads;
+                DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> >    mRecordThreads;
 
                 DefaultKeyedVector< pid_t, sp<NotificationClient> >    mNotificationClients;
-                volatile int32_t                    mNextUniqueId;
+                volatile int32_t                    mNextUniqueId;  // updated by android_atomic_inc
                 audio_mode_t                        mMode;
                 bool                                mBtNrecIsOff;
 
+                // protected by mLock
                 Vector<AudioSessionRef*> mAudioSessionRefs;
 
                 float       masterVolume_l() const  { return mMasterVolume; }
                 bool        masterMute_l() const    { return mMasterMute; }
+
+private:
+    sp<Client>  registerPid_l(pid_t pid);    // always returns non-0
+
 };
 
 
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index a8102e5..cb7678b 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioMixer.cpp
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
@@ -48,9 +48,10 @@
     mState.enabledTracks= 0;
     mState.needsChanged = 0;
     mState.frameCount   = frameCount;
+    mState.hook         = process__nop;
     mState.outputTemp   = NULL;
     mState.resampleTemp = NULL;
-    mState.hook         = process__nop;
+    // mState.reserved
     track_t* t = mState.tracks;
     for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) {
         t->needs = 0;
@@ -67,15 +68,16 @@
         // t->prevAuxLevel
         // t->frameCount
         t->channelCount = 2;
-        t->enabled = 0;
+        t->enabled = false;
         t->format = 16;
         t->channelMask = AUDIO_CHANNEL_OUT_STEREO;
-        t->buffer.raw = 0;
         t->bufferProvider = NULL;
+        t->buffer.raw = NULL;
+        // t->buffer.frameCount
         t->hook = NULL;
+        t->in = NULL;
         t->resampler = NULL;
         t->sampleRate = mSampleRate;
-        t->in = NULL;
         t->mainBuffer = NULL;
         t->auxBuffer = NULL;
         t++;
@@ -119,11 +121,11 @@
     assert(uint32_t(name) < MAX_NUM_TRACKS);
     ALOGV("deleteTrackName(%d)", name);
     track_t& track(mState.tracks[ name ]);
-    if (track.enabled != 0) {
-        track.enabled = 0;
+    if (track.enabled) {
+        track.enabled = false;
         invalidateState(1<<name);
     }
-    if (track.resampler) {
+    if (track.resampler != NULL) {
         // delete  the resampler
         delete track.resampler;
         track.resampler = NULL;
@@ -141,8 +143,8 @@
     assert(uint32_t(name) < MAX_NUM_TRACKS);
     track_t& track = mState.tracks[name];
 
-    if (track.enabled != 1) {
-        track.enabled = 1;
+    if (!track.enabled) {
+        track.enabled = true;
         ALOGV("enable(%d)", name);
         invalidateState(1 << name);
     }
@@ -154,8 +156,8 @@
     assert(uint32_t(name) < MAX_NUM_TRACKS);
     track_t& track = mState.tracks[name];
 
-    if (track.enabled != 0) {
-        track.enabled = 0;
+    if (track.enabled) {
+        track.enabled = false;
         ALOGV("disable(%d)", name);
         invalidateState(1 << name);
     }
@@ -294,18 +296,6 @@
     return false;
 }
 
-bool AudioMixer::track_t::doesResample() const
-{
-    return resampler != NULL;
-}
-
-void AudioMixer::track_t::resetResampler()
-{
-    if (resampler != NULL) {
-        resampler->reset();
-    }
-}
-
 inline
 void AudioMixer::track_t::adjustVolumeRamp(bool aux)
 {
@@ -325,20 +315,11 @@
     }
 }
 
-size_t AudioMixer::track_t::getUnreleasedFrames()
-{
-    if (resampler != NULL) {
-        return resampler->getUnreleasedFrames();
-    }
-    return 0;
-}
-
-size_t AudioMixer::getUnreleasedFrames(int name)
+size_t AudioMixer::getUnreleasedFrames(int name) const
 {
     name -= TRACK0;
     if (uint32_t(name) < MAX_NUM_TRACKS) {
-        track_t& track(mState.tracks[name]);
-        return track.getUnreleasedFrames();
+        return mState.tracks[name].getUnreleasedFrames();
     }
     return 0;
 }
@@ -381,9 +362,9 @@
 
     // compute everything we need...
     int countActiveTracks = 0;
-    int all16BitsStereoNoResample = 1;
-    int resampling = 0;
-    int volumeRamp = 0;
+    bool all16BitsStereoNoResample = true;
+    bool resampling = false;
+    bool volumeRamp = false;
     uint32_t en = state->enabledTracks;
     while (en) {
         const int i = 31 - __builtin_clz(en);
@@ -400,7 +381,7 @@
         }
 
         if (t.volumeInc[0]|t.volumeInc[1]) {
-            volumeRamp = 1;
+            volumeRamp = true;
         } else if (!t.doesResample() && t.volumeRL == 0) {
             n |= NEEDS_MUTE_ENABLED;
         }
@@ -410,16 +391,16 @@
             t.hook = track__nop;
         } else {
             if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
-                all16BitsStereoNoResample = 0;
+                all16BitsStereoNoResample = false;
             }
             if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
-                all16BitsStereoNoResample = 0;
-                resampling = 1;
+                all16BitsStereoNoResample = false;
+                resampling = true;
                 t.hook = track__genericResample;
             } else {
                 if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
                     t.hook = track__16BitsMono;
-                    all16BitsStereoNoResample = 0;
+                    all16BitsStereoNoResample = false;
                 }
                 if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_2){
                     t.hook = track__16BitsStereo;
@@ -467,7 +448,7 @@
     // Now that the volume ramp has been done, set optimal state and
     // track hooks for subsequent mixer process
     if (countActiveTracks) {
-        int allMuted = 1;
+        bool allMuted = true;
         uint32_t en = state->enabledTracks;
         while (en) {
             const int i = 31 - __builtin_clz(en);
@@ -478,7 +459,7 @@
                 t.needs |= NEEDS_MUTE_ENABLED;
                 t.hook = track__nop;
             } else {
-                allMuted = 0;
+                allMuted = false;
             }
         }
         if (allMuted) {
@@ -807,7 +788,7 @@
             while (outFrames) {
                 t1.buffer.frameCount = outFrames;
                 t1.bufferProvider->getNextBuffer(&t1.buffer);
-                if (!t1.buffer.raw) break;
+                if (t1.buffer.raw == NULL) break;
                 outFrames -= t1.buffer.frameCount;
                 t1.bufferProvider->releaseBuffer(&t1.buffer);
             }
@@ -980,7 +961,12 @@
 // one track, 16 bits stereo without resampling is the most common case
 void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
 {
+    // This method is only called when state->enabledTracks has exactly
+    // one bit set.  The asserts below would verify this, but are commented out
+    // since the whole point of this method is to optimize performance.
+    //assert(0 != state->enabledTracks);
     const int i = 31 - __builtin_clz(state->enabledTracks);
+    //assert((1 << i) == state->enabledTracks);
     const track_t& t = state->tracks[i];
 
     AudioBufferProvider::Buffer& b(t.buffer);
@@ -1127,9 +1113,7 @@
         }
     }
 
-    if (buff != NULL) {
-        delete [] buff;
-    }
+    delete [] buff;
 }
 #endif
 
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 84f6330..c956918 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioMixer.h
+/*
 **
 ** Copyright 2007, The Android Open Source Project
 **
@@ -33,7 +33,7 @@
 public:
                             AudioMixer(size_t frameCount, uint32_t sampleRate);
 
-                            ~AudioMixer();
+    /*virtual*/             ~AudioMixer();  // non-virtual saves a v-table, restore if sub-classed
 
     static const uint32_t MAX_NUM_TRACKS = 32;
     static const uint32_t MAX_NUM_CHANNELS = 2;
@@ -83,7 +83,7 @@
 
     uint32_t    trackNames() const { return mTrackNames; }
 
-    size_t      getUnreleasedFrames(int name);
+    size_t      getUnreleasedFrames(int name) const;
 
 private:
 
@@ -153,10 +153,11 @@
         int32_t*           auxBuffer;
 
         bool        setResampler(uint32_t sampleRate, uint32_t devSampleRate);
-        bool        doesResample() const;
-        void        resetResampler();
+        bool        doesResample() const { return resampler != NULL; }
+        void        resetResampler() { if (resampler != NULL) resampler->reset(); }
         void        adjustVolumeRamp(bool aux);
-        size_t      getUnreleasedFrames();
+        size_t      getUnreleasedFrames() const { return resampler != NULL ?
+                                                    resampler->getUnreleasedFrames() : 0; };
     };
 
     // pad to 32-bytes to fill cache line
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 28b1c89..041b5a8 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -30,6 +30,7 @@
 #include <utils/String16.h>
 #include <utils/threads.h>
 #include "AudioPolicyService.h"
+#include "ServiceUtilities.h"
 #include <cutils/properties.h>
 #include <hardware_legacy/power.h>
 #include <media/AudioEffect.h>
@@ -49,13 +50,6 @@
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleepUs = 20000;
 
-static bool checkPermission() {
-    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
-    bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
-    if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
-    return ok;
-}
-
 namespace {
     extern struct audio_policy_service_ops aps_ops;
 };
@@ -144,9 +138,9 @@
     }
     mInputs.clear();
 
-    if (mpAudioPolicy && mpAudioPolicyDev)
+    if (mpAudioPolicy != NULL && mpAudioPolicyDev != NULL)
         mpAudioPolicyDev->destroy_audio_policy(mpAudioPolicyDev, mpAudioPolicy);
-    if (mpAudioPolicyDev)
+    if (mpAudioPolicyDev != NULL)
         audio_policy_dev_close(mpAudioPolicyDev);
 }
 
@@ -157,7 +151,7 @@
     if (mpAudioPolicy == NULL) {
         return NO_INIT;
     }
-    if (!checkPermission()) {
+    if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
     if (!audio_is_output_device(device) && !audio_is_input_device(device)) {
@@ -190,7 +184,7 @@
     if (mpAudioPolicy == NULL) {
         return NO_INIT;
     }
-    if (!checkPermission()) {
+    if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
     if (uint32_t(state) >= AUDIO_MODE_CNT) {
@@ -213,7 +207,7 @@
     if (mpAudioPolicy == NULL) {
         return NO_INIT;
     }
-    if (!checkPermission()) {
+    if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
     if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
@@ -287,7 +281,7 @@
     mpAudioPolicy->release_output(mpAudioPolicy, output);
 }
 
-audio_io_handle_t AudioPolicyService::getInput(int inputSource,
+audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource,
                                     uint32_t samplingRate,
                                     audio_format_t format,
                                     uint32_t channels,
@@ -297,6 +291,10 @@
     if (mpAudioPolicy == NULL) {
         return 0;
     }
+    // already checked by client, but double-check in case the client wrapper is bypassed
+    if (uint32_t(inputSource) >= AUDIO_SOURCE_CNT) {
+        return 0;
+    }
     Mutex::Autolock _l(mLock);
     audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
                                                        format, channels, acoustics);
@@ -305,7 +303,7 @@
         return input;
     }
     // create audio pre processors according to input source
-    ssize_t index = mInputSources.indexOfKey((audio_source_t)inputSource);
+    ssize_t index = mInputSources.indexOfKey(inputSource);
     if (index < 0) {
         return input;
     }
@@ -384,7 +382,7 @@
     if (mpAudioPolicy == NULL) {
         return NO_INIT;
     }
-    if (!checkPermission()) {
+    if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
@@ -401,7 +399,7 @@
     if (mpAudioPolicy == NULL) {
         return NO_INIT;
     }
-    if (!checkPermission()) {
+    if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
@@ -538,7 +536,7 @@
 }
 
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
-    ALOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(),
+    ALOGW("binderDied() %p, tid %d, calling pid %d", who.unsafe_get(), gettid(),
             IPCThreadState::self()->getCallingPid());
 }
 
@@ -574,7 +572,7 @@
 
 status_t AudioPolicyService::dump(int fd, const Vector<String16>& args)
 {
-    if (!checkCallingPermission(String16("android.permission.DUMP"))) {
+    if (!dumpAllowed()) {
         dumpPermissionDenial(fd);
     } else {
         bool locked = tryLock(mLock);
@@ -584,10 +582,10 @@
         }
 
         dumpInternals(fd);
-        if (mAudioCommandThread != NULL) {
+        if (mAudioCommandThread != 0) {
             mAudioCommandThread->dump(fd);
         }
-        if (mTonePlaybackThread != NULL) {
+        if (mTonePlaybackThread != 0) {
             mTonePlaybackThread->dump(fd);
         }
 
@@ -645,7 +643,7 @@
         release_wake_lock(mName.string());
     }
     mAudioCommands.clear();
-    if (mpToneGenerator != NULL) delete mpToneGenerator;
+    delete mpToneGenerator;
 }
 
 void AudioPolicyService::AudioCommandThread::onFirstRef()
@@ -678,8 +676,7 @@
                     ToneData *data = (ToneData *)command->mParam;
                     ALOGV("AudioCommandThread() processing start tone %d on stream %d",
                             data->mType, data->mStream);
-                    if (mpToneGenerator != NULL)
-                        delete mpToneGenerator;
+                    delete mpToneGenerator;
                     mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
                     mpToneGenerator->startTone(data->mType);
                     delete data;
@@ -771,7 +768,7 @@
     snprintf(buffer, SIZE, "- Commands:\n");
     result = String8(buffer);
     result.append("   Command Time        Wait pParam\n");
-    for (int i = 0; i < (int)mAudioCommands.size(); i++) {
+    for (size_t i = 0; i < mAudioCommands.size(); i++) {
         mAudioCommands[i]->dump(buffer, SIZE);
         result.append(buffer);
     }
@@ -786,7 +783,8 @@
     return NO_ERROR;
 }
 
-void AudioPolicyService::AudioCommandThread::startToneCommand(int type, audio_stream_type_t stream)
+void AudioPolicyService::AudioCommandThread::startToneCommand(ToneGenerator::tone_type type,
+        audio_stream_type_t stream)
 {
     AudioCommand *command = new AudioCommand();
     command->mCommand = START_TONE;
@@ -815,7 +813,7 @@
 
 status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
                                                                float volume,
-                                                               int output,
+                                                               audio_io_handle_t output,
                                                                int delayMs)
 {
     status_t status = NO_ERROR;
@@ -845,7 +843,7 @@
     return status;
 }
 
-status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle,
+status_t AudioPolicyService::AudioCommandThread::parametersCommand(audio_io_handle_t ioHandle,
                                                                    const char *keyValuePairs,
                                                                    int delayMs)
 {
@@ -904,7 +902,7 @@
 // insertCommand_l() must be called with mLock held
 void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
 {
-    ssize_t i;
+    ssize_t i;  // not size_t because i will count down to -1
     Vector <AudioCommand *> removedCommands;
 
     command->mTime = systemTime() + milliseconds(delayMs);
@@ -1015,7 +1013,7 @@
                                        const char *keyValuePairs,
                                        int delayMs)
 {
-    mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs,
+    mAudioCommandThread->parametersCommand(ioHandle, keyValuePairs,
                                            delayMs);
 }
 
@@ -1025,7 +1023,7 @@
                                         int delayMs)
 {
     return (int)mAudioCommandThread->volumeCommand(stream, volume,
-                                                   (int)output, delayMs);
+                                                   output, delayMs);
 }
 
 int AudioPolicyService::startTone(audio_policy_tone_t tone,
@@ -1156,7 +1154,7 @@
     if (param == NULL && value == NULL) {
         // try to parse simple parameter form {int int}
         param = root->first_child;
-        if (param) {
+        if (param != NULL) {
             // Note: that a pair of random strings is read as 0 0
             int *ptr = (int *)fx_param->data;
             int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
@@ -1358,7 +1356,7 @@
                                              audio_policy_output_flags_t flags)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == NULL) {
+    if (af == 0) {
         ALOGW("%s: could not get AudioFlinger", __func__);
         return 0;
     }
@@ -1372,7 +1370,7 @@
                                                  audio_io_handle_t output2)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == NULL) {
+    if (af == 0) {
         ALOGW("%s: could not get AudioFlinger", __func__);
         return 0;
     }
@@ -1382,7 +1380,7 @@
 static int aps_close_output(void *service, audio_io_handle_t output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == NULL)
+    if (af == 0)
         return PERMISSION_DENIED;
 
     return af->closeOutput(output);
@@ -1391,7 +1389,7 @@
 static int aps_suspend_output(void *service, audio_io_handle_t output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == NULL) {
+    if (af == 0) {
         ALOGW("%s: could not get AudioFlinger", __func__);
         return PERMISSION_DENIED;
     }
@@ -1402,7 +1400,7 @@
 static int aps_restore_output(void *service, audio_io_handle_t output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == NULL) {
+    if (af == 0) {
         ALOGW("%s: could not get AudioFlinger", __func__);
         return PERMISSION_DENIED;
     }
@@ -1415,10 +1413,10 @@
                                             uint32_t *pSamplingRate,
                                             audio_format_t *pFormat,
                                             uint32_t *pChannels,
-                                            uint32_t acoustics)
+                                            audio_in_acoustics_t acoustics)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == NULL) {
+    if (af == 0) {
         ALOGW("%s: could not get AudioFlinger", __func__);
         return 0;
     }
@@ -1430,7 +1428,7 @@
 static int aps_close_input(void *service, audio_io_handle_t input)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == NULL)
+    if (af == 0)
         return PERMISSION_DENIED;
 
     return af->closeInput(input);
@@ -1440,7 +1438,7 @@
                                      audio_io_handle_t output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == NULL)
+    if (af == 0)
         return PERMISSION_DENIED;
 
     return af->setStreamOutput(stream, output);
@@ -1451,10 +1449,10 @@
                                 audio_io_handle_t dst_output)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == NULL)
+    if (af == 0)
         return PERMISSION_DENIED;
 
-    return af->moveEffects(session, (int)src_output, (int)dst_output);
+    return af->moveEffects(session, src_output, dst_output);
 }
 
 static char * aps_get_parameters(void *service, audio_io_handle_t io_handle,
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index 9811670..fdaf576 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -74,12 +74,12 @@
                                 audio_stream_type_t stream,
                                 int session = 0);
     virtual void releaseOutput(audio_io_handle_t output);
-    virtual audio_io_handle_t getInput(int inputSource,
+    virtual audio_io_handle_t getInput(audio_source_t inputSource,
                                     uint32_t samplingRate = 0,
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                     uint32_t channels = 0,
                                     audio_in_acoustics_t acoustics =
-                                            (audio_in_acoustics_t)0,
+                                            (audio_in_acoustics_t)0 /*AUDIO_IN_ACOUSTICS_NONE*/,
                                     int audioSession = 0);
     virtual status_t startInput(audio_io_handle_t input);
     virtual status_t stopInput(audio_io_handle_t input);
@@ -171,10 +171,13 @@
         virtual     bool        threadLoop();
 
                     void        exit();
-                    void        startToneCommand(int type = 0, audio_stream_type_t stream = AUDIO_STREAM_VOICE_CALL);
+                    void        startToneCommand(ToneGenerator::tone_type type,
+                                                 audio_stream_type_t stream);
                     void        stopToneCommand();
-                    status_t    volumeCommand(audio_stream_type_t stream, float volume, int output, int delayMs = 0);
-                    status_t    parametersCommand(int ioHandle, const char *keyValuePairs, int delayMs = 0);
+                    status_t    volumeCommand(audio_stream_type_t stream, float volume,
+                                            audio_io_handle_t output, int delayMs = 0);
+                    status_t    parametersCommand(audio_io_handle_t ioHandle,
+                                            const char *keyValuePairs, int delayMs = 0);
                     status_t    voiceVolumeCommand(float volume, int delayMs = 0);
                     void        insertCommand_l(AudioCommand *command, int delayMs = 0);
 
@@ -198,7 +201,7 @@
 
         class ToneData {
         public:
-            int mType;      // tone type (START_TONE only)
+            ToneGenerator::tone_type mType; // tone type (START_TONE only)
             audio_stream_type_t mStream;    // stream type (START_TONE only)
         };
 
@@ -206,12 +209,12 @@
         public:
             audio_stream_type_t mStream;
             float mVolume;
-            int mIO;
+            audio_io_handle_t mIO;
         };
 
         class ParametersData {
         public:
-            int mIO;
+            audio_io_handle_t mIO;
             String8 mKeyValuePairs;
         };
 
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index feacd96..9486b9c 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -23,8 +23,10 @@
 #include <cutils/log.h>
 #include <cutils/properties.h>
 #include "AudioResampler.h"
+#if 0
 #include "AudioResamplerSinc.h"
 #include "AudioResamplerCubic.h"
+#endif
 
 #ifdef __arm__
 #include <machine/cpu-features.h>
@@ -99,6 +101,7 @@
         ALOGV("Create linear Resampler");
         resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
         break;
+#if 0
     case MED_QUALITY:
         ALOGV("Create cubic Resampler");
         resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
@@ -107,6 +110,7 @@
         ALOGV("Create sinc Resampler");
         resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
         break;
+#endif
     }
 
     // initialize resampler
@@ -130,12 +134,6 @@
     mVolume[0] = mVolume[1] = 0;
     mBuffer.frameCount = 0;
 
-    // save format for quick lookup
-    if (inChannelCount == 1) {
-        mFormat = MONO_16_BIT;
-    } else {
-        mFormat = STEREO_16_BIT;
-    }
 }
 
 AudioResampler::~AudioResampler() {
@@ -190,7 +188,7 @@
     size_t outputSampleCount = outFrameCount * 2;
     size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
 
-    // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+    // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
 
     while (outputIndex < outputSampleCount) {
@@ -203,7 +201,7 @@
                 goto resampleStereo16_exit;
             }
 
-            // ALOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+            // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
             if (mBuffer.frameCount > inputIndex) break;
 
             inputIndex -= mBuffer.frameCount;
@@ -217,7 +215,7 @@
 
         // handle boundary case
         while (inputIndex == 0) {
-            // ALOGE("boundary case\n");
+            // ALOGE("boundary case");
             out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
             out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
             Advance(&inputIndex, &phaseFraction, phaseIncrement);
@@ -226,7 +224,7 @@
         }
 
         // process input samples
-        // ALOGE("general case\n");
+        // ALOGE("general case");
 
 #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
         if (inputIndex + 2 < mBuffer.frameCount) {
@@ -248,7 +246,7 @@
             Advance(&inputIndex, &phaseFraction, phaseIncrement);
         }
 
-        // ALOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+        // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
 
         // if done with buffer, save samples
         if (inputIndex >= mBuffer.frameCount) {
@@ -265,7 +263,7 @@
         }
     }
 
-    // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+    // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
 
 resampleStereo16_exit:
     // save state
@@ -286,7 +284,7 @@
     size_t outputSampleCount = outFrameCount * 2;
     size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
 
-    // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
+    // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
     while (outputIndex < outputSampleCount) {
         // buffer is empty, fetch a new one
@@ -298,7 +296,7 @@
                 mPhaseFraction = phaseFraction;
                 goto resampleMono16_exit;
             }
-            // ALOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
+            // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
             if (mBuffer.frameCount >  inputIndex) break;
 
             inputIndex -= mBuffer.frameCount;
@@ -310,7 +308,7 @@
 
         // handle boundary case
         while (inputIndex == 0) {
-            // ALOGE("boundary case\n");
+            // ALOGE("boundary case");
             int32_t sample = Interp(mX0L, in[0], phaseFraction);
             out[outputIndex++] += vl * sample;
             out[outputIndex++] += vr * sample;
@@ -320,7 +318,7 @@
         }
 
         // process input samples
-        // ALOGE("general case\n");
+        // ALOGE("general case");
 
 #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
         if (inputIndex + 2 < mBuffer.frameCount) {
@@ -343,7 +341,7 @@
         }
 
 
-        // ALOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+        // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
 
         // if done with buffer, save samples
         if (inputIndex >= mBuffer.frameCount) {
@@ -359,7 +357,7 @@
         }
     }
 
-    // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
+    // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
 
 resampleMono16_exit:
     // save state
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index ffa690a..c23016e 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -54,7 +54,7 @@
             AudioBufferProvider* provider) = 0;
 
     virtual void reset();
-    virtual size_t getUnreleasedFrames() { return mInputIndex; }
+    virtual size_t getUnreleasedFrames() const { return mInputIndex; }
 
 protected:
     // number of bits for phase fraction - 30 bits allows nearly 2x downsampling
@@ -66,16 +66,15 @@
     // multiplier to calculate fixed point phase increment
     static const double kPhaseMultiplier = 1L << kNumPhaseBits;
 
-    enum format {MONO_16_BIT, STEREO_16_BIT};
     AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate);
 
     // prevent copying
     AudioResampler(const AudioResampler&);
     AudioResampler& operator=(const AudioResampler&);
 
-    int32_t mBitDepth;
-    int32_t mChannelCount;
-    int32_t mSampleRate;
+    const int32_t mBitDepth;
+    const int32_t mChannelCount;
+    const int32_t mSampleRate;
     int32_t mInSampleRate;
     AudioBufferProvider::Buffer mBuffer;
     union {
@@ -83,7 +82,6 @@
         uint32_t mVolumeRL;
     };
     int16_t mTargetVolume[2];
-    format mFormat;
     size_t mInputIndex;
     int32_t mPhaseIncrement;
     uint32_t mPhaseFraction;
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 47205ba..c0e760e 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -99,7 +99,7 @@
                 if (mBuffer.raw == NULL)
                     goto save_state;  // ugly, but efficient
                 in = mBuffer.i16;
-                // ALOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+                // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
             }
 
             // advance sample state
@@ -133,7 +133,7 @@
         provider->getNextBuffer(&mBuffer);
         if (mBuffer.raw == NULL)
             return;
-        // ALOGW("New buffer: offset=%p, frames=%d\n", mBuffer.raw, mBuffer.frameCount);
+        // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
     }
     int16_t *in = mBuffer.i16;
 
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index d012433..7a27b81 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -199,33 +199,32 @@
     size_t outputSampleCount = outFrameCount * 2;
     size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
 
-    AudioBufferProvider::Buffer& buffer(mBuffer);
     while (outputIndex < outputSampleCount) {
         // buffer is empty, fetch a new one
-        while (buffer.frameCount == 0) {
-            buffer.frameCount = inFrameCount;
-            provider->getNextBuffer(&buffer);
-            if (buffer.raw == NULL) {
+        while (mBuffer.frameCount == 0) {
+            mBuffer.frameCount = inFrameCount;
+            provider->getNextBuffer(&mBuffer);
+            if (mBuffer.raw == NULL) {
                 goto resample_exit;
             }
             const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
             if (phaseIndex == 1) {
                 // read one frame
-                read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+                read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
             } else if (phaseIndex == 2) {
                 // read 2 frames
-                read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+                read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
                 inputIndex++;
                 if (inputIndex >= mBuffer.frameCount) {
                     inputIndex -= mBuffer.frameCount;
-                    provider->releaseBuffer(&buffer);
+                    provider->releaseBuffer(&mBuffer);
                 } else {
-                    read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+                    read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
                 }
            }
         }
-        int16_t *in = buffer.i16;
-        const size_t frameCount = buffer.frameCount;
+        int16_t *in = mBuffer.i16;
+        const size_t frameCount = mBuffer.frameCount;
 
         // Always read-in the first samples from the input buffer
         int16_t* head = impulse + halfNumCoefs*CHANNELS;
@@ -264,7 +263,7 @@
         // if done with buffer, save samples
         if (inputIndex >= frameCount) {
             inputIndex -= frameCount;
-            provider->releaseBuffer(&buffer);
+            provider->releaseBuffer(&mBuffer);
         }
     }
 
diff --git a/services/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h
index 0e1bc44..f0a07b8 100644
--- a/services/audioflinger/AudioResamplerSinc.h
+++ b/services/audioflinger/AudioResamplerSinc.h
@@ -31,7 +31,7 @@
 public:
     AudioResamplerSinc(int bitDepth, int inChannelCount, int32_t sampleRate);
 
-    ~AudioResamplerSinc();
+    virtual ~AudioResamplerSinc();
 
     virtual void resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider);
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
new file mode 100644
index 0000000..6a58852
--- /dev/null
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include "ServiceUtilities.h"
+
+namespace android {
+
+// This optimization assumes mediaserver process doesn't fork, which it doesn't
+const pid_t getpid_cached = getpid();
+
+bool recordingAllowed() {
+    if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+    static const String16 sRecordAudio("android.permission.RECORD_AUDIO");
+    // don't use PermissionCache; this is not a system permission
+    bool ok = checkCallingPermission(sRecordAudio);
+    if (!ok) ALOGE("Request requires android.permission.RECORD_AUDIO");
+    return ok;
+}
+
+bool settingsAllowed() {
+    if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+    static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
+    // don't use PermissionCache; this is not a system permission
+    bool ok = checkCallingPermission(sAudioSettings);
+    if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+    return ok;
+}
+
+bool dumpAllowed() {
+    // don't optimize for same pid, since mediaserver never dumps itself
+    static const String16 sDump("android.permission.DUMP");
+    // OK to use PermissionCache; this is a system permission
+    bool ok = PermissionCache::checkCallingPermission(sDump);
+    // convention is for caller to dump an error message to fd instead of logging here
+    //if (!ok) ALOGE("Request requires android.permission.DUMP");
+    return ok;
+}
+
+} // namespace android
diff --git a/libs/rs/rsFifo.cpp b/services/audioflinger/ServiceUtilities.h
similarity index 70%
rename from libs/rs/rsFifo.cpp
rename to services/audioflinger/ServiceUtilities.h
index 3d5d8c4..f77ec5bc 100644
--- a/libs/rs/rsFifo.cpp
+++ b/services/audioflinger/ServiceUtilities.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -14,18 +14,14 @@
  * limitations under the License.
  */
 
-#include "rsFifoSocket.h"
-#include "utils/Timers.h"
-#include "utils/StopWatch.h"
+#include <unistd.h>
 
-using namespace android;
-using namespace android::renderscript;
+namespace android {
 
-Fifo::Fifo() {
+extern const pid_t getpid_cached;
+
+bool recordingAllowed();
+bool settingsAllowed();
+bool dumpAllowed();
 
 }
-
-Fifo::~Fifo() {
-
-}
-
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 1f8cf63..296c95e 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -831,7 +831,7 @@
 
     ALOGV("Opening device: %s", devicePath);
 
-    int fd = open(devicePath, O_RDWR);
+    int fd = open(devicePath, O_RDWR | O_CLOEXEC);
     if(fd < 0) {
         ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
         return -1;
@@ -1063,14 +1063,20 @@
         return -1;
     }
 
+    // Enable wake-lock behavior on kernels that support it.
+    // TODO: Only need this for devices that can really wake the system.
+    bool usingSuspendBlock = ioctl(fd, EVIOCSSUSPENDBLOCK, 1) == 0;
+
     ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
-            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",
+            "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
+            "usingSuspendBlock=%s",
          deviceId, fd, devicePath, device->identifier.name.string(),
          device->classes,
          device->configurationFile.string(),
          device->keyMap.keyLayoutFile.string(),
          device->keyMap.keyCharacterMapFile.string(),
-         toString(mBuiltInKeyboardId == deviceId));
+         toString(mBuiltInKeyboardId == deviceId),
+         toString(usingSuspendBlock));
 
     mDevices.add(deviceId, device);
 
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 9f09062..d4e59d1 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -24,24 +24,15 @@
 // Log detailed debug messages about each outbound event processed by the dispatcher.
 #define DEBUG_OUTBOUND_EVENT_DETAILS 0
 
-// Log debug messages about batching.
-#define DEBUG_BATCHING 0
-
 // Log debug messages about the dispatch cycle.
 #define DEBUG_DISPATCH_CYCLE 0
 
 // Log debug messages about registrations.
 #define DEBUG_REGISTRATION 0
 
-// Log debug messages about performance statistics.
-#define DEBUG_PERFORMANCE_STATISTICS 0
-
 // Log debug messages about input event injection.
 #define DEBUG_INJECTION 0
 
-// Log debug messages about input event throttling.
-#define DEBUG_THROTTLING 0
-
 // Log debug messages about input focus tracking.
 #define DEBUG_FOCUS 0
 
@@ -79,21 +70,11 @@
 // before considering it stale and dropping it.
 const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
 
-// Motion samples that are received within this amount of time are simply coalesced
-// when batched instead of being appended.  This is done because some drivers update
-// the location of pointers one at a time instead of all at once.
-// For example, when there are 10 fingers down, the input dispatcher may receive 10
-// samples in quick succession with only one finger's location changed in each sample.
-//
-// This value effectively imposes an upper bound on the touch sampling rate.
-// Touch sensors typically have a 50Hz - 200Hz sampling rate, so we expect distinct
-// samples to become available 5-20ms apart but individual finger reports can trickle
-// in over a period of 2-4ms or so.
-//
-// Empirical testing shows that a 2ms coalescing interval (500Hz) is not enough,
-// a 3ms coalescing interval (333Hz) works well most of the time and doesn't introduce
-// significant quantization noise on current hardware.
-const nsecs_t MOTION_SAMPLE_COALESCE_INTERVAL = 3 * 1000000LL; // 3ms, 333Hz
+// Amount of time to allow touch events to be streamed out to a connection before requiring
+// that the first event be finished.  This value extends the ANR timeout by the specified
+// amount.  For example, if streaming is allowed to get ahead by one second relative to the
+// queue of waiting unfinished events, then ANRs will similarly be delayed by one second.
+const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec
 
 
 static inline nsecs_t now() {
@@ -203,21 +184,12 @@
     mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
     mNextUnblockedEvent(NULL),
     mDispatchEnabled(true), mDispatchFrozen(false), mInputFilterEnabled(false),
-    mCurrentInputTargetsValid(false),
     mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
     mLooper = new Looper(false);
 
     mKeyRepeatState.lastKeyEntry = NULL;
 
     policy->getDispatcherConfiguration(&mConfig);
-
-    mThrottleState.minTimeBetweenEvents = 1000000000LL / mConfig.maxEventsPerSecond;
-    mThrottleState.lastDeviceId = -1;
-
-#if DEBUG_THROTTLING
-    mThrottleState.originalSampleCount = 0;
-    ALOGD("Throttling - Max events per second = %d", mConfig.maxEventsPerSecond);
-#endif
 }
 
 InputDispatcher::~InputDispatcher() {
@@ -229,8 +201,8 @@
         drainInboundQueueLocked();
     }
 
-    while (mConnectionsByReceiveFd.size() != 0) {
-        unregisterInputChannel(mConnectionsByReceiveFd.valueAt(0)->inputChannel);
+    while (mConnectionsByFd.size() != 0) {
+        unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel);
     }
 }
 
@@ -238,6 +210,8 @@
     nsecs_t nextWakeupTime = LONG_LONG_MAX;
     { // acquire lock
         AutoMutex _l(mLock);
+        mDispatcherIsAliveCondition.broadcast();
+
         dispatchOnceInnerLocked(&nextWakeupTime);
 
         if (runCommandsLockedInterruptible()) {
@@ -300,78 +274,21 @@
             }
 
             // Nothing to do if there is no pending event.
-            if (! mPendingEvent) {
-                if (mActiveConnections.isEmpty()) {
-                    dispatchIdleLocked();
-                }
+            if (!mPendingEvent) {
                 return;
             }
         } else {
             // Inbound queue has at least one entry.
-            EventEntry* entry = mInboundQueue.head;
-
-            // Throttle the entry if it is a move event and there are no
-            // other events behind it in the queue.  Due to movement batching, additional
-            // samples may be appended to this event by the time the throttling timeout
-            // expires.
-            // TODO Make this smarter and consider throttling per device independently.
-            if (entry->type == EventEntry::TYPE_MOTION
-                    && !isAppSwitchDue
-                    && mDispatchEnabled
-                    && (entry->policyFlags & POLICY_FLAG_PASS_TO_USER)
-                    && !entry->isInjected()) {
-                MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
-                int32_t deviceId = motionEntry->deviceId;
-                uint32_t source = motionEntry->source;
-                if (! isAppSwitchDue
-                        && !motionEntry->next // exactly one event, no successors
-                        && (motionEntry->action == AMOTION_EVENT_ACTION_MOVE
-                                || motionEntry->action == AMOTION_EVENT_ACTION_HOVER_MOVE)
-                        && deviceId == mThrottleState.lastDeviceId
-                        && source == mThrottleState.lastSource) {
-                    nsecs_t nextTime = mThrottleState.lastEventTime
-                            + mThrottleState.minTimeBetweenEvents;
-                    if (currentTime < nextTime) {
-                        // Throttle it!
-#if DEBUG_THROTTLING
-                        ALOGD("Throttling - Delaying motion event for "
-                                "device %d, source 0x%08x by up to %0.3fms.",
-                                deviceId, source, (nextTime - currentTime) * 0.000001);
-#endif
-                        if (nextTime < *nextWakeupTime) {
-                            *nextWakeupTime = nextTime;
-                        }
-                        if (mThrottleState.originalSampleCount == 0) {
-                            mThrottleState.originalSampleCount =
-                                    motionEntry->countSamples();
-                        }
-                        return;
-                    }
-                }
-
-#if DEBUG_THROTTLING
-                if (mThrottleState.originalSampleCount != 0) {
-                    uint32_t count = motionEntry->countSamples();
-                    ALOGD("Throttling - Motion event sample count grew by %d from %d to %d.",
-                            count - mThrottleState.originalSampleCount,
-                            mThrottleState.originalSampleCount, count);
-                    mThrottleState.originalSampleCount = 0;
-                }
-#endif
-
-                mThrottleState.lastEventTime = currentTime;
-                mThrottleState.lastDeviceId = deviceId;
-                mThrottleState.lastSource = source;
-            }
-
-            mInboundQueue.dequeue(entry);
-            mPendingEvent = entry;
+            mPendingEvent = mInboundQueue.dequeueAtHead();
         }
 
         // Poke user activity for this event.
         if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
             pokeUserActivityLocked(mPendingEvent);
         }
+
+        // Get ready to dispatch the event.
+        resetANRTimeoutsLocked();
     }
 
     // Now we have an event to dispatch.
@@ -459,16 +376,6 @@
     }
 }
 
-void InputDispatcher::dispatchIdleLocked() {
-#if DEBUG_FOCUS
-    ALOGD("Dispatcher idle.  There are no pending events or active connections.");
-#endif
-
-    // Reset targets when idle, to release input channels and other resources
-    // they are holding onto.
-    resetTargetsLocked();
-}
-
 bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
     bool needWake = mInboundQueue.isEmpty();
     mInboundQueue.enqueueAtTail(entry);
@@ -506,9 +413,9 @@
                 && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                 && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
                 && mInputTargetWaitApplicationHandle != NULL) {
-            int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0].
+            int32_t x = int32_t(motionEntry->pointerCoords[0].
                     getAxisValue(AMOTION_EVENT_AXIS_X));
-            int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0].
+            int32_t y = int32_t(motionEntry->pointerCoords[0].
                     getAxisValue(AMOTION_EVENT_AXIS_Y));
             sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y);
             if (touchedWindowHandle != NULL
@@ -669,6 +576,7 @@
 
 void InputDispatcher::releasePendingEventLocked() {
     if (mPendingEvent) {
+        resetANRTimeoutsLocked();
         releaseInboundEventLocked(mPendingEvent);
         mPendingEvent = NULL;
     }
@@ -791,7 +699,6 @@
         }
 
         entry->dispatchInProgress = true;
-        resetTargetsLocked();
 
         logOutboundKeyDetailsLocked("dispatchKey - ", entry);
     }
@@ -830,31 +737,28 @@
 
     // Clean up if dropping the event.
     if (*dropReason != DROP_REASON_NOT_DROPPED) {
-        resetTargetsLocked();
         setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                 ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
         return true;
     }
 
     // Identify targets.
-    if (! mCurrentInputTargetsValid) {
-        int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
-                entry, nextWakeupTime);
-        if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
-            return false;
-        }
-
-        setInjectionResultLocked(entry, injectionResult);
-        if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
-            return true;
-        }
-
-        addMonitoringTargetsLocked();
-        commitTargetsLocked();
+    Vector<InputTarget> inputTargets;
+    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
+            entry, inputTargets, nextWakeupTime);
+    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
+        return false;
     }
 
+    setInjectionResultLocked(entry, injectionResult);
+    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
+        return true;
+    }
+
+    addMonitoringTargetsLocked(inputTargets);
+
     // Dispatch the key.
-    dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
+    dispatchEventLocked(currentTime, entry, inputTargets);
     return true;
 }
 
@@ -875,14 +779,12 @@
     // Preprocessing.
     if (! entry->dispatchInProgress) {
         entry->dispatchInProgress = true;
-        resetTargetsLocked();
 
         logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
     }
 
     // Clean up if dropping the event.
     if (*dropReason != DROP_REASON_NOT_DROPPED) {
-        resetTargetsLocked();
         setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
                 ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
         return true;
@@ -891,67 +793,29 @@
     bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
 
     // Identify targets.
+    Vector<InputTarget> inputTargets;
+
     bool conflictingPointerActions = false;
-    if (! mCurrentInputTargetsValid) {
-        int32_t injectionResult;
-        const MotionSample* splitBatchAfterSample = NULL;
-        if (isPointerEvent) {
-            // Pointer event.  (eg. touchscreen)
-            injectionResult = findTouchedWindowTargetsLocked(currentTime,
-                    entry, nextWakeupTime, &conflictingPointerActions, &splitBatchAfterSample);
-        } else {
-            // Non touch event.  (eg. trackball)
-            injectionResult = findFocusedWindowTargetsLocked(currentTime,
-                    entry, nextWakeupTime);
-        }
-        if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
-            return false;
-        }
-
-        setInjectionResultLocked(entry, injectionResult);
-        if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
-            return true;
-        }
-
-        addMonitoringTargetsLocked();
-        commitTargetsLocked();
-
-        // Unbatch the event if necessary by splitting it into two parts after the
-        // motion sample indicated by splitBatchAfterSample.
-        if (splitBatchAfterSample && splitBatchAfterSample->next) {
-#if DEBUG_BATCHING
-            uint32_t originalSampleCount = entry->countSamples();
-#endif
-            MotionSample* nextSample = splitBatchAfterSample->next;
-            MotionEntry* nextEntry = new MotionEntry(nextSample->eventTime,
-                    entry->deviceId, entry->source, entry->policyFlags,
-                    entry->action, entry->flags,
-                    entry->metaState, entry->buttonState, entry->edgeFlags,
-                    entry->xPrecision, entry->yPrecision, entry->downTime,
-                    entry->pointerCount, entry->pointerProperties, nextSample->pointerCoords);
-            if (nextSample != entry->lastSample) {
-                nextEntry->firstSample.next = nextSample->next;
-                nextEntry->lastSample = entry->lastSample;
-            }
-            delete nextSample;
-
-            entry->lastSample = const_cast<MotionSample*>(splitBatchAfterSample);
-            entry->lastSample->next = NULL;
-
-            if (entry->injectionState) {
-                nextEntry->injectionState = entry->injectionState;
-                entry->injectionState->refCount += 1;
-            }
-
-#if DEBUG_BATCHING
-            ALOGD("Split batch of %d samples into two parts, first part has %d samples, "
-                    "second part has %d samples.", originalSampleCount,
-                    entry->countSamples(), nextEntry->countSamples());
-#endif
-
-            mInboundQueue.enqueueAtHead(nextEntry);
-        }
+    int32_t injectionResult;
+    if (isPointerEvent) {
+        // Pointer event.  (eg. touchscreen)
+        injectionResult = findTouchedWindowTargetsLocked(currentTime,
+                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
+    } else {
+        // Non touch event.  (eg. trackball)
+        injectionResult = findFocusedWindowTargetsLocked(currentTime,
+                entry, inputTargets, nextWakeupTime);
     }
+    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
+        return false;
+    }
+
+    setInjectionResultLocked(entry, injectionResult);
+    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
+        return true;
+    }
+
+    addMonitoringTargetsLocked(inputTargets);
 
     // Dispatch the motion.
     if (conflictingPointerActions) {
@@ -959,7 +823,7 @@
                 "conflicting pointer actions");
         synthesizeCancelationEventsForAllConnectionsLocked(options);
     }
-    dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
+    dispatchEventLocked(currentTime, entry, inputTargets);
     return true;
 }
 
@@ -977,12 +841,6 @@
             entry->edgeFlags, entry->xPrecision, entry->yPrecision,
             entry->downTime);
 
-    // Print the most recent sample that we have available, this may change due to batching.
-    size_t sampleCount = 1;
-    const MotionSample* sample = & entry->firstSample;
-    for (; sample->next != NULL; sample = sample->next) {
-        sampleCount += 1;
-    }
     for (uint32_t i = 0; i < entry->pointerCount; i++) {
         ALOGD("  Pointer %d: id=%d, toolType=%d, "
                 "x=%f, y=%f, pressure=%f, size=%f, "
@@ -990,45 +848,36 @@
                 "orientation=%f",
                 i, entry->pointerProperties[i].id,
                 entry->pointerProperties[i].toolType,
-                sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
-                sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
-                sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
-                sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
-                sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
-                sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
-                sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
-                sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
-                sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
-    }
-
-    // Keep in mind that due to batching, it is possible for the number of samples actually
-    // dispatched to change before the application finally consumed them.
-    if (entry->action == AMOTION_EVENT_ACTION_MOVE) {
-        ALOGD("  ... Total movement samples currently batched %d ...", sampleCount);
+                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
+                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
+                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+                entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
     }
 #endif
 }
 
-void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
-        EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
+void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
+        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
 #if DEBUG_DISPATCH_CYCLE
-    ALOGD("dispatchEventToCurrentInputTargets - "
-            "resumeWithAppendedMotionSample=%s",
-            toString(resumeWithAppendedMotionSample));
+    ALOGD("dispatchEventToCurrentInputTargets");
 #endif
 
     ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
 
     pokeUserActivityLocked(eventEntry);
 
-    for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
-        const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
+    for (size_t i = 0; i < inputTargets.size(); i++) {
+        const InputTarget& inputTarget = inputTargets.itemAt(i);
 
         ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
         if (connectionIndex >= 0) {
-            sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
-            prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
-                    resumeWithAppendedMotionSample);
+            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
         } else {
 #if DEBUG_FOCUS
             ALOGD("Dropping event delivery to target with channel '%s' because it "
@@ -1039,16 +888,6 @@
     }
 }
 
-void InputDispatcher::resetTargetsLocked() {
-    mCurrentInputTargetsValid = false;
-    mCurrentInputTargets.clear();
-    resetANRTimeoutsLocked();
-}
-
-void InputDispatcher::commitTargetsLocked() {
-    mCurrentInputTargetsValid = true;
-}
-
 int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
         const EventEntry* entry,
         const sp<InputApplicationHandle>& applicationHandle,
@@ -1133,7 +972,7 @@
         if (inputChannel.get()) {
             ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
             if (connectionIndex >= 0) {
-                sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+                sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
                 if (connection->status == Connection::STATUS_NORMAL) {
                     CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
                             "application not responding");
@@ -1163,9 +1002,7 @@
 }
 
 int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
-        const EventEntry* entry, nsecs_t* nextWakeupTime) {
-    mCurrentInputTargets.clear();
-
+        const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
     int32_t injectionResult;
 
     // If there is no currently focused window and no focused application
@@ -1204,7 +1041,7 @@
     }
 
     // If the currently focused window is still working on previous events then keep waiting.
-    if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindowHandle)) {
+    if (!isWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry)) {
 #if DEBUG_FOCUS
         ALOGD("Waiting because focused window still processing previous input.");
 #endif
@@ -1216,7 +1053,8 @@
     // Success!  Output targets.
     injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
     addWindowTargetLocked(mFocusedWindowHandle,
-            InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0));
+            InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
+            inputTargets);
 
     // Done.
 Failed:
@@ -1233,16 +1071,14 @@
 }
 
 int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
-        const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
-        const MotionSample** outSplitBatchAfterSample) {
+        const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+        bool* outConflictingPointerActions) {
     enum InjectionPermission {
         INJECTION_PERMISSION_UNKNOWN,
         INJECTION_PERMISSION_GRANTED,
         INJECTION_PERMISSION_DENIED
     };
 
-    mCurrentInputTargets.clear();
-
     nsecs_t startTime = now();
 
     // For security reasons, we defer updating the touch state until we are sure that
@@ -1314,11 +1150,10 @@
     if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
         /* Case 1: New splittable pointer going down, or need target for hover or scroll. */
 
-        const MotionSample* sample = &entry->firstSample;
         int32_t pointerIndex = getMotionEventActionPointerIndex(action);
-        int32_t x = int32_t(sample->pointerCoords[pointerIndex].
+        int32_t x = int32_t(entry->pointerCoords[pointerIndex].
                 getAxisValue(AMOTION_EVENT_AXIS_X));
-        int32_t y = int32_t(sample->pointerCoords[pointerIndex].
+        int32_t y = int32_t(entry->pointerCoords[pointerIndex].
                 getAxisValue(AMOTION_EVENT_AXIS_Y));
         sp<InputWindowHandle> newTouchedWindowHandle;
         sp<InputWindowHandle> topErrorWindowHandle;
@@ -1418,21 +1253,6 @@
         // Update hover state.
         if (isHoverAction) {
             newHoverWindowHandle = newTouchedWindowHandle;
-
-            // Ensure all subsequent motion samples are also within the touched window.
-            // Set *outSplitBatchAfterSample to the sample before the first one that is not
-            // within the touched window.
-            if (!isTouchModal) {
-                while (sample->next) {
-                    if (!newHoverWindowHandle->getInfo()->touchableRegionContainsPoint(
-                            sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
-                            sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) {
-                        *outSplitBatchAfterSample = sample;
-                        break;
-                    }
-                    sample = sample->next;
-                }
-            }
         } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
             newHoverWindowHandle = mLastHoverWindowHandle;
         }
@@ -1461,9 +1281,8 @@
         if (maskedAction == AMOTION_EVENT_ACTION_MOVE
                 && entry->pointerCount == 1
                 && mTempTouchState.isSlippery()) {
-            const MotionSample* sample = &entry->firstSample;
-            int32_t x = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
-            int32_t y = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
+            int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
+            int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
 
             sp<InputWindowHandle> oldTouchedWindowHandle =
                     mTempTouchState.getFirstForegroundWindowHandle();
@@ -1498,17 +1317,11 @@
                     pointerIds.markBit(entry->pointerProperties[0].id);
                 }
                 mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
-
-                // Split the batch here so we send exactly one sample.
-                *outSplitBatchAfterSample = &entry->firstSample;
             }
         }
     }
 
     if (newHoverWindowHandle != mLastHoverWindowHandle) {
-        // Split the batch here so we send exactly one sample as part of ENTER or EXIT.
-        *outSplitBatchAfterSample = &entry->firstSample;
-
         // Let the previous window know that the hover sequence is over.
         if (mLastHoverWindowHandle != NULL) {
 #if DEBUG_HOVER
@@ -1591,7 +1404,7 @@
             }
 
             // If the touched window is still working on previous events then keep waiting.
-            if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.windowHandle)) {
+            if (!isWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry)) {
 #if DEBUG_FOCUS
                 ALOGD("Waiting because touched window still processing previous input.");
 #endif
@@ -1631,7 +1444,7 @@
     for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
         const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
         addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
-                touchedWindow.pointerIds);
+                touchedWindow.pointerIds, inputTargets);
     }
 
     // Drop the outside or hover touch windows since we will not care about them
@@ -1736,11 +1549,11 @@
 }
 
 void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
-        int32_t targetFlags, BitSet32 pointerIds) {
-    mCurrentInputTargets.push();
+        int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) {
+    inputTargets.push();
 
     const InputWindowInfo* windowInfo = windowHandle->getInfo();
-    InputTarget& target = mCurrentInputTargets.editTop();
+    InputTarget& target = inputTargets.editTop();
     target.inputChannel = windowInfo->inputChannel;
     target.flags = targetFlags;
     target.xOffset = - windowInfo->frameLeft;
@@ -1749,11 +1562,11 @@
     target.pointerIds = pointerIds;
 }
 
-void InputDispatcher::addMonitoringTargetsLocked() {
+void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets) {
     for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
-        mCurrentInputTargets.push();
+        inputTargets.push();
 
-        InputTarget& target = mCurrentInputTargets.editTop();
+        InputTarget& target = inputTargets.editTop();
         target.inputChannel = mMonitoringChannels[i];
         target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
         target.xOffset = 0;
@@ -1802,15 +1615,51 @@
     return false;
 }
 
-bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(
-        const sp<InputWindowHandle>& windowHandle) {
+bool InputDispatcher::isWindowReadyForMoreInputLocked(nsecs_t currentTime,
+        const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry) {
     ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
     if (connectionIndex >= 0) {
-        sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
-        return connection->outboundQueue.isEmpty();
-    } else {
-        return true;
+        sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+        if (connection->inputPublisherBlocked) {
+            return false;
+        }
+        if (eventEntry->type == EventEntry::TYPE_KEY) {
+            // If the event is a key event, then we must wait for all previous events to
+            // complete before delivering it because previous events may have the
+            // side-effect of transferring focus to a different window and we want to
+            // ensure that the following keys are sent to the new window.
+            //
+            // Suppose the user touches a button in a window then immediately presses "A".
+            // If the button causes a pop-up window to appear then we want to ensure that
+            // the "A" key is delivered to the new pop-up window.  This is because users
+            // often anticipate pending UI changes when typing on a keyboard.
+            // To obtain this behavior, we must serialize key events with respect to all
+            // prior input events.
+            return connection->outboundQueue.isEmpty()
+                    && connection->waitQueue.isEmpty();
+        }
+        // Touch events can always be sent to a window immediately because the user intended
+        // to touch whatever was visible at the time.  Even if focus changes or a new
+        // window appears moments later, the touch event was meant to be delivered to
+        // whatever window happened to be on screen at the time.
+        //
+        // Generic motion events, such as trackball or joystick events are a little trickier.
+        // Like key events, generic motion events are delivered to the focused window.
+        // Unlike key events, generic motion events don't tend to transfer focus to other
+        // windows and it is not important for them to be serialized.  So we prefer to deliver
+        // generic motion events as soon as possible to improve efficiency and reduce lag
+        // through batching.
+        //
+        // The one case where we pause input event delivery is when the wait queue is piling
+        // up with lots of events because the application is not responding.
+        // This condition ensures that ANRs are detected reliably.
+        if (!connection->waitQueue.isEmpty()
+                && currentTime >= connection->waitQueue.head->eventEntry->eventTime
+                        + STREAM_AHEAD_EVENT_TIMEOUT) {
+            return false;
+        }
     }
+    return true;
 }
 
 String8 InputDispatcher::getApplicationWindowLabelLocked(
@@ -1863,23 +1712,16 @@
 }
 
 void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
-        bool resumeWithAppendedMotionSample) {
+        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
             "xOffset=%f, yOffset=%f, scaleFactor=%f, "
-            "pointerIds=0x%x, "
-            "resumeWithAppendedMotionSample=%s",
+            "pointerIds=0x%x",
             connection->getInputChannelName(), inputTarget->flags,
             inputTarget->xOffset, inputTarget->yOffset,
-            inputTarget->scaleFactor, inputTarget->pointerIds.value,
-            toString(resumeWithAppendedMotionSample));
+            inputTarget->scaleFactor, inputTarget->pointerIds.value);
 #endif
 
-    // Make sure we are never called for streaming when splitting across multiple windows.
-    bool isSplit = inputTarget->flags & InputTarget::FLAG_SPLIT;
-    ALOG_ASSERT(! (resumeWithAppendedMotionSample && isSplit));
-
     // Skip this event if the connection status is not normal.
     // We don't want to enqueue additional outbound events if the connection is broken.
     if (connection->status != Connection::STATUS_NORMAL) {
@@ -1891,7 +1733,7 @@
     }
 
     // Split a motion event if needed.
-    if (isSplit) {
+    if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
         ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);
 
         MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
@@ -1907,145 +1749,43 @@
             logOutboundMotionDetailsLocked("  ", splitMotionEntry);
 #endif
             enqueueDispatchEntriesLocked(currentTime, connection,
-                    splitMotionEntry, inputTarget, resumeWithAppendedMotionSample);
+                    splitMotionEntry, inputTarget);
             splitMotionEntry->release();
             return;
         }
     }
 
     // Not splitting.  Enqueue dispatch entries for the event as is.
-    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget,
-            resumeWithAppendedMotionSample);
+    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
 }
 
 void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
-        bool resumeWithAppendedMotionSample) {
-    // Resume the dispatch cycle with a freshly appended motion sample.
-    // First we check that the last dispatch entry in the outbound queue is for the same
-    // motion event to which we appended the motion sample.  If we find such a dispatch
-    // entry, and if it is currently in progress then we try to stream the new sample.
+        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
     bool wasEmpty = connection->outboundQueue.isEmpty();
 
-    if (! wasEmpty && resumeWithAppendedMotionSample) {
-        DispatchEntry* motionEventDispatchEntry =
-                connection->findQueuedDispatchEntryForEvent(eventEntry);
-        if (motionEventDispatchEntry) {
-            // If the dispatch entry is not in progress, then we must be busy dispatching an
-            // earlier event.  Not a problem, the motion event is on the outbound queue and will
-            // be dispatched later.
-            if (! motionEventDispatchEntry->inProgress) {
-#if DEBUG_BATCHING
-                ALOGD("channel '%s' ~ Not streaming because the motion event has "
-                        "not yet been dispatched.  "
-                        "(Waiting for earlier events to be consumed.)",
-                        connection->getInputChannelName());
-#endif
-                return;
-            }
-
-            // If the dispatch entry is in progress but it already has a tail of pending
-            // motion samples, then it must mean that the shared memory buffer filled up.
-            // Not a problem, when this dispatch cycle is finished, we will eventually start
-            // a new dispatch cycle to process the tail and that tail includes the newly
-            // appended motion sample.
-            if (motionEventDispatchEntry->tailMotionSample) {
-#if DEBUG_BATCHING
-                ALOGD("channel '%s' ~ Not streaming because no new samples can "
-                        "be appended to the motion event in this dispatch cycle.  "
-                        "(Waiting for next dispatch cycle to start.)",
-                        connection->getInputChannelName());
-#endif
-                return;
-            }
-
-            // If the motion event was modified in flight, then we cannot stream the sample.
-            if ((motionEventDispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_MASK)
-                    != InputTarget::FLAG_DISPATCH_AS_IS) {
-#if DEBUG_BATCHING
-                ALOGD("channel '%s' ~ Not streaming because the motion event was not "
-                        "being dispatched as-is.  "
-                        "(Waiting for next dispatch cycle to start.)",
-                        connection->getInputChannelName());
-#endif
-                return;
-            }
-
-            // The dispatch entry is in progress and is still potentially open for streaming.
-            // Try to stream the new motion sample.  This might fail if the consumer has already
-            // consumed the motion event (or if the channel is broken).
-            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
-            MotionSample* appendedMotionSample = motionEntry->lastSample;
-            status_t status;
-            if (motionEventDispatchEntry->scaleFactor == 1.0f) {
-                status = connection->inputPublisher.appendMotionSample(
-                        appendedMotionSample->eventTime, appendedMotionSample->pointerCoords);
-            } else {
-                PointerCoords scaledCoords[MAX_POINTERS];
-                for (size_t i = 0; i < motionEntry->pointerCount; i++) {
-                    scaledCoords[i] = appendedMotionSample->pointerCoords[i];
-                    scaledCoords[i].scale(motionEventDispatchEntry->scaleFactor);
-                }
-                status = connection->inputPublisher.appendMotionSample(
-                        appendedMotionSample->eventTime, scaledCoords);
-            }
-            if (status == OK) {
-#if DEBUG_BATCHING
-                ALOGD("channel '%s' ~ Successfully streamed new motion sample.",
-                        connection->getInputChannelName());
-#endif
-                return;
-            }
-
-#if DEBUG_BATCHING
-            if (status == NO_MEMORY) {
-                ALOGD("channel '%s' ~ Could not append motion sample to currently "
-                        "dispatched move event because the shared memory buffer is full.  "
-                        "(Waiting for next dispatch cycle to start.)",
-                        connection->getInputChannelName());
-            } else if (status == status_t(FAILED_TRANSACTION)) {
-                ALOGD("channel '%s' ~ Could not append motion sample to currently "
-                        "dispatched move event because the event has already been consumed.  "
-                        "(Waiting for next dispatch cycle to start.)",
-                        connection->getInputChannelName());
-            } else {
-                ALOGD("channel '%s' ~ Could not append motion sample to currently "
-                        "dispatched move event due to an error, status=%d.  "
-                        "(Waiting for next dispatch cycle to start.)",
-                        connection->getInputChannelName(), status);
-            }
-#endif
-            // Failed to stream.  Start a new tail of pending motion samples to dispatch
-            // in the next cycle.
-            motionEventDispatchEntry->tailMotionSample = appendedMotionSample;
-            return;
-        }
-    }
-
     // Enqueue dispatch entries for the requested modes.
     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
+            InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
+            InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
+            InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_IS);
+            InputTarget::FLAG_DISPATCH_AS_IS);
     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
+            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
     enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
-            resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
+            InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
 
     // If the outbound queue was previously empty, start the dispatch cycle going.
     if (wasEmpty && !connection->outboundQueue.isEmpty()) {
-        activateConnectionLocked(connection.get());
         startDispatchCycleLocked(currentTime, connection);
     }
 }
 
 void InputDispatcher::enqueueDispatchEntryLocked(
         const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
-        bool resumeWithAppendedMotionSample, int32_t dispatchMode) {
+        int32_t dispatchMode) {
     int32_t inputTargetFlags = inputTarget->flags;
     if (!(inputTargetFlags & dispatchMode)) {
         return;
@@ -2058,20 +1798,6 @@
             inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
             inputTarget->scaleFactor);
 
-    // Handle the case where we could not stream a new motion sample because the consumer has
-    // already consumed the motion event (otherwise the corresponding dispatch entry would
-    // still be in the outbound queue for this connection).  We set the head motion sample
-    // to the list starting with the newly appended motion sample.
-    if (resumeWithAppendedMotionSample) {
-#if DEBUG_BATCHING
-        ALOGD("channel '%s' ~ Preparing a new dispatch cycle for additional motion samples "
-                "that cannot be streamed because the motion event has already been consumed.",
-                connection->getInputChannelName());
-#endif
-        MotionSample* appendedMotionSample = static_cast<MotionEntry*>(eventEntry)->lastSample;
-        dispatchEntry->headMotionSample = appendedMotionSample;
-    }
-
     // Apply target flags and update the connection's input state.
     switch (eventEntry->type) {
     case EventEntry::TYPE_KEY: {
@@ -2150,227 +1876,128 @@
             connection->getInputChannelName());
 #endif
 
-    ALOG_ASSERT(connection->status == Connection::STATUS_NORMAL);
-    ALOG_ASSERT(! connection->outboundQueue.isEmpty());
+    while (connection->status == Connection::STATUS_NORMAL
+            && !connection->outboundQueue.isEmpty()) {
+        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
 
-    DispatchEntry* dispatchEntry = connection->outboundQueue.head;
-    ALOG_ASSERT(! dispatchEntry->inProgress);
+        // Publish the event.
+        status_t status;
+        EventEntry* eventEntry = dispatchEntry->eventEntry;
+        switch (eventEntry->type) {
+        case EventEntry::TYPE_KEY: {
+            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
 
-    // Mark the dispatch entry as in progress.
-    dispatchEntry->inProgress = true;
-
-    // Publish the event.
-    status_t status;
-    EventEntry* eventEntry = dispatchEntry->eventEntry;
-    switch (eventEntry->type) {
-    case EventEntry::TYPE_KEY: {
-        KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
-
-        // Publish the key event.
-        status = connection->inputPublisher.publishKeyEvent(
-                keyEntry->deviceId, keyEntry->source,
-                dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
-                keyEntry->keyCode, keyEntry->scanCode,
-                keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
-                keyEntry->eventTime);
-
-        if (status) {
-            ALOGE("channel '%s' ~ Could not publish key event, "
-                    "status=%d", connection->getInputChannelName(), status);
-            abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
-            return;
-        }
-        break;
-    }
-
-    case EventEntry::TYPE_MOTION: {
-        MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
-
-        // If headMotionSample is non-NULL, then it points to the first new sample that we
-        // were unable to dispatch during the previous cycle so we resume dispatching from
-        // that point in the list of motion samples.
-        // Otherwise, we just start from the first sample of the motion event.
-        MotionSample* firstMotionSample = dispatchEntry->headMotionSample;
-        if (! firstMotionSample) {
-            firstMotionSample = & motionEntry->firstSample;
+            // Publish the key event.
+            status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
+                    keyEntry->deviceId, keyEntry->source,
+                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
+                    keyEntry->keyCode, keyEntry->scanCode,
+                    keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
+                    keyEntry->eventTime);
+            break;
         }
 
-        PointerCoords scaledCoords[MAX_POINTERS];
-        const PointerCoords* usingCoords = firstMotionSample->pointerCoords;
+        case EventEntry::TYPE_MOTION: {
+            MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
 
-        // Set the X and Y offset depending on the input source.
-        float xOffset, yOffset, scaleFactor;
-        if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER
-                && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
-            scaleFactor = dispatchEntry->scaleFactor;
-            xOffset = dispatchEntry->xOffset * scaleFactor;
-            yOffset = dispatchEntry->yOffset * scaleFactor;
-            if (scaleFactor != 1.0f) {
-                for (size_t i = 0; i < motionEntry->pointerCount; i++) {
-                    scaledCoords[i] = firstMotionSample->pointerCoords[i];
-                    scaledCoords[i].scale(scaleFactor);
-                }
-                usingCoords = scaledCoords;
-            }
-        } else {
-            xOffset = 0.0f;
-            yOffset = 0.0f;
-            scaleFactor = 1.0f;
+            PointerCoords scaledCoords[MAX_POINTERS];
+            const PointerCoords* usingCoords = motionEntry->pointerCoords;
 
-            // We don't want the dispatch target to know.
-            if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
-                for (size_t i = 0; i < motionEntry->pointerCount; i++) {
-                    scaledCoords[i].clear();
-                }
-                usingCoords = scaledCoords;
-            }
-        }
-
-        // Publish the motion event and the first motion sample.
-        status = connection->inputPublisher.publishMotionEvent(
-                motionEntry->deviceId, motionEntry->source,
-                dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
-                motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
-                xOffset, yOffset,
-                motionEntry->xPrecision, motionEntry->yPrecision,
-                motionEntry->downTime, firstMotionSample->eventTime,
-                motionEntry->pointerCount, motionEntry->pointerProperties,
-                usingCoords);
-
-        if (status) {
-            ALOGE("channel '%s' ~ Could not publish motion event, "
-                    "status=%d", connection->getInputChannelName(), status);
-            abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
-            return;
-        }
-
-        if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_MOVE
-                || dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-            // Append additional motion samples.
-            MotionSample* nextMotionSample = firstMotionSample->next;
-            for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
-                if (usingCoords == scaledCoords) {
-                    if (!(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
-                        for (size_t i = 0; i < motionEntry->pointerCount; i++) {
-                            scaledCoords[i] = nextMotionSample->pointerCoords[i];
-                            scaledCoords[i].scale(scaleFactor);
-                        }
+            // Set the X and Y offset depending on the input source.
+            float xOffset, yOffset, scaleFactor;
+            if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
+                    && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
+                scaleFactor = dispatchEntry->scaleFactor;
+                xOffset = dispatchEntry->xOffset * scaleFactor;
+                yOffset = dispatchEntry->yOffset * scaleFactor;
+                if (scaleFactor != 1.0f) {
+                    for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+                        scaledCoords[i] = motionEntry->pointerCoords[i];
+                        scaledCoords[i].scale(scaleFactor);
                     }
-                } else {
-                    usingCoords = nextMotionSample->pointerCoords;
+                    usingCoords = scaledCoords;
                 }
-                status = connection->inputPublisher.appendMotionSample(
-                        nextMotionSample->eventTime, usingCoords);
-                if (status == NO_MEMORY) {
+            } else {
+                xOffset = 0.0f;
+                yOffset = 0.0f;
+                scaleFactor = 1.0f;
+
+                // We don't want the dispatch target to know.
+                if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
+                    for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+                        scaledCoords[i].clear();
+                    }
+                    usingCoords = scaledCoords;
+                }
+            }
+
+            // Publish the motion event.
+            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
+                    motionEntry->deviceId, motionEntry->source,
+                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
+                    motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
+                    xOffset, yOffset,
+                    motionEntry->xPrecision, motionEntry->yPrecision,
+                    motionEntry->downTime, motionEntry->eventTime,
+                    motionEntry->pointerCount, motionEntry->pointerProperties,
+                    usingCoords);
+            break;
+        }
+
+        default:
+            ALOG_ASSERT(false);
+            return;
+        }
+
+        // Check the result.
+        if (status) {
+            if (status == WOULD_BLOCK) {
+                if (connection->waitQueue.isEmpty()) {
+                    ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
+                            "This is unexpected because the wait queue is empty, so the pipe "
+                            "should be empty and we shouldn't have any problems writing an "
+                            "event to it, status=%d", connection->getInputChannelName(), status);
+                    abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
+                } else {
+                    // Pipe is full and we are waiting for the app to finish process some events
+                    // before sending more events to it.
 #if DEBUG_DISPATCH_CYCLE
-                    ALOGD("channel '%s' ~ Shared memory buffer full.  Some motion samples will "
-                            "be sent in the next dispatch cycle.",
+                    ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
+                            "waiting for the application to catch up",
                             connection->getInputChannelName());
 #endif
-                    break;
+                    connection->inputPublisherBlocked = true;
                 }
-                if (status != OK) {
-                    ALOGE("channel '%s' ~ Could not append motion sample "
-                            "for a reason other than out of memory, status=%d",
-                            connection->getInputChannelName(), status);
-                    abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
-                    return;
-                }
+            } else {
+                ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
+                        "status=%d", connection->getInputChannelName(), status);
+                abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
             }
-
-            // Remember the next motion sample that we could not dispatch, in case we ran out
-            // of space in the shared memory buffer.
-            dispatchEntry->tailMotionSample = nextMotionSample;
+            return;
         }
-        break;
-    }
 
-    default: {
-        ALOG_ASSERT(false);
+        // Re-enqueue the event on the wait queue.
+        connection->outboundQueue.dequeue(dispatchEntry);
+        connection->waitQueue.enqueueAtTail(dispatchEntry);
     }
-    }
-
-    // Send the dispatch signal.
-    status = connection->inputPublisher.sendDispatchSignal();
-    if (status) {
-        ALOGE("channel '%s' ~ Could not send dispatch signal, status=%d",
-                connection->getInputChannelName(), status);
-        abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
-        return;
-    }
-
-    // Record information about the newly started dispatch cycle.
-    connection->lastEventTime = eventEntry->eventTime;
-    connection->lastDispatchTime = currentTime;
-
-    // Notify other system components.
-    onDispatchCycleStartedLocked(currentTime, connection);
 }
 
 void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection, bool handled) {
+        const sp<Connection>& connection, uint32_t seq, bool handled) {
 #if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "
-            "%01.1fms since dispatch, handled=%s",
-            connection->getInputChannelName(),
-            connection->getEventLatencyMillis(currentTime),
-            connection->getDispatchLatencyMillis(currentTime),
-            toString(handled));
+    ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
+            connection->getInputChannelName(), seq, toString(handled));
 #endif
 
+    connection->inputPublisherBlocked = false;
+
     if (connection->status == Connection::STATUS_BROKEN
             || connection->status == Connection::STATUS_ZOMBIE) {
         return;
     }
 
-    // Reset the publisher since the event has been consumed.
-    // We do this now so that the publisher can release some of its internal resources
-    // while waiting for the next dispatch cycle to begin.
-    status_t status = connection->inputPublisher.reset();
-    if (status) {
-        ALOGE("channel '%s' ~ Could not reset publisher, status=%d",
-                connection->getInputChannelName(), status);
-        abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
-        return;
-    }
-
     // Notify other system components and prepare to start the next dispatch cycle.
-    onDispatchCycleFinishedLocked(currentTime, connection, handled);
-}
-
-void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime,
-        const sp<Connection>& connection) {
-    // Start the next dispatch cycle for this connection.
-    while (! connection->outboundQueue.isEmpty()) {
-        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
-        if (dispatchEntry->inProgress) {
-             // Finish or resume current event in progress.
-            if (dispatchEntry->tailMotionSample) {
-                // We have a tail of undispatched motion samples.
-                // Reuse the same DispatchEntry and start a new cycle.
-                dispatchEntry->inProgress = false;
-                dispatchEntry->headMotionSample = dispatchEntry->tailMotionSample;
-                dispatchEntry->tailMotionSample = NULL;
-                startDispatchCycleLocked(currentTime, connection);
-                return;
-            }
-            // Finished.
-            connection->outboundQueue.dequeueAtHead();
-            if (dispatchEntry->hasForegroundTarget()) {
-                decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
-            }
-            delete dispatchEntry;
-        } else {
-            // If the head is not in progress, then we must have already dequeued the in
-            // progress event, which means we actually aborted it.
-            // So just start the next event for this connection.
-            startDispatchCycleLocked(currentTime, connection);
-            return;
-        }
-    }
-
-    // Outbound queue is empty, deactivate the connection.
-    deactivateConnectionLocked(connection.get());
+    onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
 }
 
 void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
@@ -2380,8 +2007,9 @@
             connection->getInputChannelName(), toString(notify));
 #endif
 
-    // Clear the outbound queue.
-    drainOutboundQueueLocked(connection.get());
+    // Clear the dispatch queues.
+    drainDispatchQueueLocked(&connection->outboundQueue);
+    drainDispatchQueueLocked(&connection->waitQueue);
 
     // The connection appears to be unrecoverably broken.
     // Ignore already broken or zombie connections.
@@ -2395,33 +2023,35 @@
     }
 }
 
-void InputDispatcher::drainOutboundQueueLocked(Connection* connection) {
-    while (! connection->outboundQueue.isEmpty()) {
-        DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
-        if (dispatchEntry->hasForegroundTarget()) {
-            decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
-        }
-        delete dispatchEntry;
+void InputDispatcher::drainDispatchQueueLocked(Queue<DispatchEntry>* queue) {
+    while (!queue->isEmpty()) {
+        DispatchEntry* dispatchEntry = queue->dequeueAtHead();
+        releaseDispatchEntryLocked(dispatchEntry);
     }
-
-    deactivateConnectionLocked(connection);
 }
 
-int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
+void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) {
+    if (dispatchEntry->hasForegroundTarget()) {
+        decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
+    }
+    delete dispatchEntry;
+}
+
+int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
     InputDispatcher* d = static_cast<InputDispatcher*>(data);
 
     { // acquire lock
         AutoMutex _l(d->mLock);
 
-        ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd);
+        ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
         if (connectionIndex < 0) {
             ALOGE("Received spurious receive callback for unknown input channel.  "
-                    "fd=%d, events=0x%x", receiveFd, events);
+                    "fd=%d, events=0x%x", fd, events);
             return 0; // remove the callback
         }
 
         bool notify;
-        sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
+        sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
         if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
             if (!(events & ALOOPER_EVENT_INPUT)) {
                 ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
@@ -2429,18 +2059,31 @@
                 return 1;
             }
 
-            bool handled = false;
-            status_t status = connection->inputPublisher.receiveFinishedSignal(&handled);
-            if (!status) {
-                nsecs_t currentTime = now();
-                d->finishDispatchCycleLocked(currentTime, connection, handled);
+            nsecs_t currentTime = now();
+            bool gotOne = false;
+            status_t status;
+            for (;;) {
+                uint32_t seq;
+                bool handled;
+                status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
+                if (status) {
+                    break;
+                }
+                d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
+                gotOne = true;
+            }
+            if (gotOne) {
                 d->runCommandsLockedInterruptible();
-                return 1;
+                if (status == WOULD_BLOCK) {
+                    return 1;
+                }
             }
 
-            ALOGE("channel '%s' ~ Failed to receive finished signal.  status=%d",
-                    connection->getInputChannelName(), status);
-            notify = true;
+            notify = status != DEAD_OBJECT || !connection->monitor;
+            if (notify) {
+                ALOGE("channel '%s' ~ Failed to receive finished signal.  status=%d",
+                        connection->getInputChannelName(), status);
+            }
         } else {
             // Monitor channels are never explicitly unregistered.
             // We do it automatically when the remote endpoint is closed so don't warn
@@ -2460,9 +2103,9 @@
 
 void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
         const CancelationOptions& options) {
-    for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
+    for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
         synthesizeCancelationEventsForConnectionLocked(
-                mConnectionsByReceiveFd.valueAt(i), options);
+                mConnectionsByFd.valueAt(i), options);
     }
 }
 
@@ -2471,7 +2114,7 @@
     ssize_t index = getConnectionIndexLocked(channel);
     if (index >= 0) {
         synthesizeCancelationEventsForConnectionLocked(
-                mConnectionsByReceiveFd.valueAt(index), options);
+                mConnectionsByFd.valueAt(index), options);
     }
 }
 
@@ -2483,19 +2126,19 @@
 
     nsecs_t currentTime = now();
 
-    mTempCancelationEvents.clear();
+    Vector<EventEntry*> cancelationEvents;
     connection->inputState.synthesizeCancelationEvents(currentTime,
-            mTempCancelationEvents, options);
+            cancelationEvents, options);
 
-    if (!mTempCancelationEvents.isEmpty()) {
+    if (!cancelationEvents.isEmpty()) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
         ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
                 "with reality: %s, mode=%d.",
-                connection->getInputChannelName(), mTempCancelationEvents.size(),
+                connection->getInputChannelName(), cancelationEvents.size(),
                 options.reason, options.mode);
 #endif
-        for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
-            EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
+        for (size_t i = 0; i < cancelationEvents.size(); i++) {
+            EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i);
             switch (cancelationEventEntry->type) {
             case EventEntry::TYPE_KEY:
                 logOutboundKeyDetailsLocked("cancel - ",
@@ -2523,14 +2166,12 @@
             target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
 
             enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
-                    &target, false, InputTarget::FLAG_DISPATCH_AS_IS);
+                    &target, InputTarget::FLAG_DISPATCH_AS_IS);
 
             cancelationEventEntry->release();
         }
 
-        if (!connection->outboundQueue.head->inProgress) {
-            startDispatchCycleLocked(currentTime, connection);
-        }
+        startDispatchCycleLocked(currentTime, connection);
     }
 }
 
@@ -2554,7 +2195,7 @@
             splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
             splitPointerProperties[splitPointerCount].copyFrom(pointerProperties);
             splitPointerCoords[splitPointerCount].copyFrom(
-                    originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]);
+                    originalMotionEntry->pointerCoords[originalPointerIndex]);
             splitPointerCount += 1;
         }
     }
@@ -2615,18 +2256,6 @@
             originalMotionEntry->downTime,
             splitPointerCount, splitPointerProperties, splitPointerCoords);
 
-    for (MotionSample* originalMotionSample = originalMotionEntry->firstSample.next;
-            originalMotionSample != NULL; originalMotionSample = originalMotionSample->next) {
-        for (uint32_t splitPointerIndex = 0; splitPointerIndex < splitPointerCount;
-                splitPointerIndex++) {
-            uint32_t originalPointerIndex = splitPointerIndexMap[splitPointerIndex];
-            splitPointerCoords[splitPointerIndex].copyFrom(
-                    originalMotionSample->pointerCoords[originalPointerIndex]);
-        }
-
-        splitMotionEntry->appendSample(originalMotionSample->eventTime, splitPointerCoords);
-    }
-
     if (originalMotionEntry->injectionState) {
         splitMotionEntry->injectionState = originalMotionEntry->injectionState;
         splitMotionEntry->injectionState->refCount += 1;
@@ -2787,163 +2416,6 @@
             mLock.lock();
         }
 
-        // Attempt batching and streaming of move events.
-        if (args->action == AMOTION_EVENT_ACTION_MOVE
-                || args->action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-            // BATCHING CASE
-            //
-            // Try to append a move sample to the tail of the inbound queue for this device.
-            // Give up if we encounter a non-move motion event for this device since that
-            // means we cannot append any new samples until a new motion event has started.
-            for (EventEntry* entry = mInboundQueue.tail; entry; entry = entry->prev) {
-                if (entry->type != EventEntry::TYPE_MOTION) {
-                    // Keep looking for motion events.
-                    continue;
-                }
-
-                MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
-                if (motionEntry->deviceId != args->deviceId
-                        || motionEntry->source != args->source) {
-                    // Keep looking for this device and source.
-                    continue;
-                }
-
-                if (!motionEntry->canAppendSamples(args->action,
-                        args->pointerCount, args->pointerProperties)) {
-                    // Last motion event in the queue for this device and source is
-                    // not compatible for appending new samples.  Stop here.
-                    goto NoBatchingOrStreaming;
-                }
-
-                // Do the batching magic.
-                batchMotionLocked(motionEntry, args->eventTime,
-                        args->metaState, args->pointerCoords,
-                        "most recent motion event for this device and source in the inbound queue");
-                mLock.unlock();
-                return; // done!
-            }
-
-            // BATCHING ONTO PENDING EVENT CASE
-            //
-            // Try to append a move sample to the currently pending event, if there is one.
-            // We can do this as long as we are still waiting to find the targets for the
-            // event.  Once the targets are locked-in we can only do streaming.
-            if (mPendingEvent
-                    && (!mPendingEvent->dispatchInProgress || !mCurrentInputTargetsValid)
-                    && mPendingEvent->type == EventEntry::TYPE_MOTION) {
-                MotionEntry* motionEntry = static_cast<MotionEntry*>(mPendingEvent);
-                if (motionEntry->deviceId == args->deviceId
-                        && motionEntry->source == args->source) {
-                    if (!motionEntry->canAppendSamples(args->action,
-                            args->pointerCount, args->pointerProperties)) {
-                        // Pending motion event is for this device and source but it is
-                        // not compatible for appending new samples.  Stop here.
-                        goto NoBatchingOrStreaming;
-                    }
-
-                    // Do the batching magic.
-                    batchMotionLocked(motionEntry, args->eventTime,
-                            args->metaState, args->pointerCoords,
-                            "pending motion event");
-                    mLock.unlock();
-                    return; // done!
-                }
-            }
-
-            // STREAMING CASE
-            //
-            // There is no pending motion event (of any kind) for this device in the inbound queue.
-            // Search the outbound queue for the current foreground targets to find a dispatched
-            // motion event that is still in progress.  If found, then, appen the new sample to
-            // that event and push it out to all current targets.  The logic in
-            // prepareDispatchCycleLocked takes care of the case where some targets may
-            // already have consumed the motion event by starting a new dispatch cycle if needed.
-            if (mCurrentInputTargetsValid) {
-                for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
-                    const InputTarget& inputTarget = mCurrentInputTargets[i];
-                    if ((inputTarget.flags & InputTarget::FLAG_FOREGROUND) == 0) {
-                        // Skip non-foreground targets.  We only want to stream if there is at
-                        // least one foreground target whose dispatch is still in progress.
-                        continue;
-                    }
-
-                    ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
-                    if (connectionIndex < 0) {
-                        // Connection must no longer be valid.
-                        continue;
-                    }
-
-                    sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
-                    if (connection->outboundQueue.isEmpty()) {
-                        // This foreground target has an empty outbound queue.
-                        continue;
-                    }
-
-                    DispatchEntry* dispatchEntry = connection->outboundQueue.head;
-                    if (! dispatchEntry->inProgress
-                            || dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION
-                            || dispatchEntry->isSplit()) {
-                        // No motion event is being dispatched, or it is being split across
-                        // windows in which case we cannot stream.
-                        continue;
-                    }
-
-                    MotionEntry* motionEntry = static_cast<MotionEntry*>(
-                            dispatchEntry->eventEntry);
-                    if (motionEntry->action != args->action
-                            || motionEntry->deviceId != args->deviceId
-                            || motionEntry->source != args->source
-                            || motionEntry->pointerCount != args->pointerCount
-                            || motionEntry->isInjected()) {
-                        // The motion event is not compatible with this move.
-                        continue;
-                    }
-
-                    if (args->action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-                        if (mLastHoverWindowHandle == NULL) {
-#if DEBUG_BATCHING
-                            ALOGD("Not streaming hover move because there is no "
-                                    "last hovered window.");
-#endif
-                            goto NoBatchingOrStreaming;
-                        }
-
-                        sp<InputWindowHandle> hoverWindowHandle = findTouchedWindowAtLocked(
-                                args->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
-                                args->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
-                        if (mLastHoverWindowHandle != hoverWindowHandle) {
-#if DEBUG_BATCHING
-                            ALOGD("Not streaming hover move because the last hovered window "
-                                    "is '%s' but the currently hovered window is '%s'.",
-                                    mLastHoverWindowHandle->getName().string(),
-                                    hoverWindowHandle != NULL
-                                            ? hoverWindowHandle->getName().string() : "<null>");
-#endif
-                            goto NoBatchingOrStreaming;
-                        }
-                    }
-
-                    // Hurray!  This foreground target is currently dispatching a move event
-                    // that we can stream onto.  Append the motion sample and resume dispatch.
-                    motionEntry->appendSample(args->eventTime, args->pointerCoords);
-#if DEBUG_BATCHING
-                    ALOGD("Appended motion sample onto batch for most recently dispatched "
-                            "motion event for this device and source in the outbound queues.  "
-                            "Attempting to stream the motion sample.");
-#endif
-                    nsecs_t currentTime = now();
-                    dispatchEventToCurrentInputTargetsLocked(currentTime, motionEntry,
-                            true /*resumeWithAppendedMotionSample*/);
-
-                    runCommandsLockedInterruptible();
-                    mLock.unlock();
-                    return; // done!
-                }
-            }
-
-NoBatchingOrStreaming:;
-        }
-
         // Just enqueue a new motion event.
         MotionEntry* newEntry = new MotionEntry(args->eventTime,
                 args->deviceId, args->source, policyFlags,
@@ -2960,36 +2432,6 @@
     }
 }
 
-void InputDispatcher::batchMotionLocked(MotionEntry* entry, nsecs_t eventTime,
-        int32_t metaState, const PointerCoords* pointerCoords, const char* eventDescription) {
-    // Combine meta states.
-    entry->metaState |= metaState;
-
-    // Coalesce this sample if not enough time has elapsed since the last sample was
-    // initially appended to the batch.
-    MotionSample* lastSample = entry->lastSample;
-    long interval = eventTime - lastSample->eventTimeBeforeCoalescing;
-    if (interval <= MOTION_SAMPLE_COALESCE_INTERVAL) {
-        uint32_t pointerCount = entry->pointerCount;
-        for (uint32_t i = 0; i < pointerCount; i++) {
-            lastSample->pointerCoords[i].copyFrom(pointerCoords[i]);
-        }
-        lastSample->eventTime = eventTime;
-#if DEBUG_BATCHING
-        ALOGD("Coalesced motion into last sample of batch for %s, events were %0.3f ms apart",
-                eventDescription, interval * 0.000001f);
-#endif
-        return;
-    }
-
-    // Append the sample.
-    entry->appendSample(eventTime, pointerCoords);
-#if DEBUG_BATCHING
-    ALOGD("Appended motion sample onto batch for %s, events were %0.3f ms apart",
-            eventDescription, interval * 0.000001f);
-#endif
-}
-
 void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
     ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchCode=%d, switchValue=%d",
@@ -3038,7 +2480,8 @@
         policyFlags |= POLICY_FLAG_TRUSTED;
     }
 
-    EventEntry* injectedEntry;
+    EventEntry* firstInjectedEntry;
+    EventEntry* lastInjectedEntry;
     switch (event->getType()) {
     case AINPUT_EVENT_TYPE_KEY: {
         const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
@@ -3061,11 +2504,12 @@
         }
 
         mLock.lock();
-        injectedEntry = new KeyEntry(keyEvent->getEventTime(),
+        firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),
                 keyEvent->getDeviceId(), keyEvent->getSource(),
                 policyFlags, action, flags,
                 keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
                 keyEvent->getRepeatCount(), keyEvent->getDownTime());
+        lastInjectedEntry = firstInjectedEntry;
         break;
     }
 
@@ -3086,7 +2530,7 @@
         mLock.lock();
         const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
         const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
-        MotionEntry* motionEntry = new MotionEntry(*sampleEventTimes,
+        firstInjectedEntry = new MotionEntry(*sampleEventTimes,
                 motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
                 action, motionEvent->getFlags(),
                 motionEvent->getMetaState(), motionEvent->getButtonState(),
@@ -3094,12 +2538,21 @@
                 motionEvent->getXPrecision(), motionEvent->getYPrecision(),
                 motionEvent->getDownTime(), uint32_t(pointerCount),
                 pointerProperties, samplePointerCoords);
+        lastInjectedEntry = firstInjectedEntry;
         for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
             sampleEventTimes += 1;
             samplePointerCoords += pointerCount;
-            motionEntry->appendSample(*sampleEventTimes, samplePointerCoords);
+            MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes,
+                    motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+                    action, motionEvent->getFlags(),
+                    motionEvent->getMetaState(), motionEvent->getButtonState(),
+                    motionEvent->getEdgeFlags(),
+                    motionEvent->getXPrecision(), motionEvent->getYPrecision(),
+                    motionEvent->getDownTime(), uint32_t(pointerCount),
+                    pointerProperties, samplePointerCoords);
+            lastInjectedEntry->next = nextInjectedEntry;
+            lastInjectedEntry = nextInjectedEntry;
         }
-        injectedEntry = motionEntry;
         break;
     }
 
@@ -3114,9 +2567,15 @@
     }
 
     injectionState->refCount += 1;
-    injectedEntry->injectionState = injectionState;
+    lastInjectedEntry->injectionState = injectionState;
 
-    bool needWake = enqueueInboundEventLocked(injectedEntry);
+    bool needWake = false;
+    for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) {
+        EventEntry* nextEntry = entry->next;
+        needWake |= enqueueInboundEventLocked(entry);
+        entry = nextEntry;
+    }
+
     mLock.unlock();
 
     if (needWake) {
@@ -3364,13 +2823,13 @@
         if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) {
             if (mFocusedApplicationHandle != inputApplicationHandle) {
                 if (mFocusedApplicationHandle != NULL) {
-                    resetTargetsLocked();
+                    resetANRTimeoutsLocked();
                     mFocusedApplicationHandle->releaseInfo();
                 }
                 mFocusedApplicationHandle = inputApplicationHandle;
             }
         } else if (mFocusedApplicationHandle != NULL) {
-            resetTargetsLocked();
+            resetANRTimeoutsLocked();
             mFocusedApplicationHandle->releaseInfo();
             mFocusedApplicationHandle.clear();
         }
@@ -3493,8 +2952,8 @@
         ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
         ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
         if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
-            sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex);
-            sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
+            sp<Connection> fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex);
+            sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex);
 
             fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
             CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -3523,7 +2982,7 @@
     resetKeyRepeatLocked();
     releasePendingEventLocked();
     drainInboundQueueLocked();
-    resetTargetsLocked();
+    resetANRTimeoutsLocked();
 
     mTouchState.reset();
     mLastHoverWindowHandle.clear();
@@ -3620,20 +3079,6 @@
 
     dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
 
-    if (!mActiveConnections.isEmpty()) {
-        dump.append(INDENT "ActiveConnections:\n");
-        for (size_t i = 0; i < mActiveConnections.size(); i++) {
-            const Connection* connection = mActiveConnections[i];
-            dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u, "
-                    "inputState.isNeutral=%s\n",
-                    i, connection->getInputChannelName(), connection->getStatusLabel(),
-                    connection->outboundQueue.count(),
-                    toString(connection->inputState.isNeutral()));
-        }
-    } else {
-        dump.append(INDENT "ActiveConnections: <none>\n");
-    }
-
     if (isAppSwitchPendingLocked()) {
         dump.appendFormat(INDENT "AppSwitch: pending, due in %01.1fms\n",
                 (mAppSwitchDueTime - now()) / 1000000.0);
@@ -3659,21 +3104,15 @@
         }
 
         sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
-        status_t status = connection->initialize();
-        if (status) {
-            ALOGE("Failed to initialize input publisher for input channel '%s', status=%d",
-                    inputChannel->getName().string(), status);
-            return status;
-        }
 
-        int32_t receiveFd = inputChannel->getReceivePipeFd();
-        mConnectionsByReceiveFd.add(receiveFd, connection);
+        int32_t fd = inputChannel->getFd();
+        mConnectionsByFd.add(fd, connection);
 
         if (monitor) {
             mMonitoringChannels.push(inputChannel);
         }
 
-        mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
+        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
 
         runCommandsLockedInterruptible();
     } // release lock
@@ -3709,14 +3148,14 @@
         return BAD_VALUE;
     }
 
-    sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
-    mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
+    sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+    mConnectionsByFd.removeItemsAt(connectionIndex);
 
     if (connection->monitor) {
         removeMonitorChannelLocked(inputChannel);
     }
 
-    mLooper->removeFd(inputChannel->getReceivePipeFd());
+    mLooper->removeFd(inputChannel->getFd());
 
     nsecs_t currentTime = now();
     abortBrokenDispatchCycleLocked(currentTime, connection, notify);
@@ -3737,9 +3176,9 @@
 }
 
 ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
-    ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
+    ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
     if (connectionIndex >= 0) {
-        sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+        sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
         if (connection->inputChannel.get() == inputChannel.get()) {
             return connectionIndex;
         }
@@ -3748,33 +3187,12 @@
     return -1;
 }
 
-void InputDispatcher::activateConnectionLocked(Connection* connection) {
-    for (size_t i = 0; i < mActiveConnections.size(); i++) {
-        if (mActiveConnections.itemAt(i) == connection) {
-            return;
-        }
-    }
-    mActiveConnections.add(connection);
-}
-
-void InputDispatcher::deactivateConnectionLocked(Connection* connection) {
-    for (size_t i = 0; i < mActiveConnections.size(); i++) {
-        if (mActiveConnections.itemAt(i) == connection) {
-            mActiveConnections.removeAt(i);
-            return;
-        }
-    }
-}
-
-void InputDispatcher::onDispatchCycleStartedLocked(
-        nsecs_t currentTime, const sp<Connection>& connection) {
-}
-
 void InputDispatcher::onDispatchCycleFinishedLocked(
-        nsecs_t currentTime, const sp<Connection>& connection, bool handled) {
+        nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
     CommandEntry* commandEntry = postCommandLocked(
             & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
     commandEntry->connection = connection;
+    commandEntry->seq = seq;
     commandEntry->handled = handled;
 }
 
@@ -3868,26 +3286,40 @@
 void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
         CommandEntry* commandEntry) {
     sp<Connection> connection = commandEntry->connection;
+    uint32_t seq = commandEntry->seq;
     bool handled = commandEntry->handled;
 
-    bool skipNext = false;
-    if (!connection->outboundQueue.isEmpty()) {
-        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
-        if (dispatchEntry->inProgress) {
-            if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
-                KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
-                skipNext = afterKeyEventLockedInterruptible(connection,
-                        dispatchEntry, keyEntry, handled);
-            } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
-                MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
-                skipNext = afterMotionEventLockedInterruptible(connection,
-                        dispatchEntry, motionEntry, handled);
+    // Handle post-event policy actions.
+    DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
+    if (dispatchEntry) {
+        bool restartEvent;
+        if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
+            KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+            restartEvent = afterKeyEventLockedInterruptible(connection,
+                    dispatchEntry, keyEntry, handled);
+        } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
+            MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
+            restartEvent = afterMotionEventLockedInterruptible(connection,
+                    dispatchEntry, motionEntry, handled);
+        } else {
+            restartEvent = false;
+        }
+
+        // Dequeue the event and start the next cycle.
+        // Note that because the lock might have been released, it is possible that the
+        // contents of the wait queue to have been drained, so we need to double-check
+        // a few things.
+        if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
+            connection->waitQueue.dequeue(dispatchEntry);
+            if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
+                connection->outboundQueue.enqueueAtHead(dispatchEntry);
+            } else {
+                releaseDispatchEntryLocked(dispatchEntry);
             }
         }
-    }
 
-    if (!skipNext) {
-        startNextDispatchCycleLocked(now(), connection);
+        // Start the next dispatch cycle for this connection.
+        startDispatchCycleLocked(now(), connection);
     }
 }
 
@@ -3951,11 +3383,9 @@
 
             if (connection->status != Connection::STATUS_NORMAL) {
                 connection->inputState.removeFallbackKey(originalKeyCode);
-                return true; // skip next cycle
+                return false;
             }
 
-            ALOG_ASSERT(connection->outboundQueue.head == dispatchEntry);
-
             // Latch the fallback keycode for this key on an initial down.
             // The fallback keycode cannot change at any other point in the lifecycle.
             if (initialDown) {
@@ -4033,10 +3463,7 @@
                         "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
                         originalKeyCode, fallbackKeyCode, keyEntry->metaState);
 #endif
-
-                dispatchEntry->inProgress = false;
-                startDispatchCycleLocked(now(), connection);
-                return true; // already started next cycle
+                return true; // restart the event
             } else {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
                 ALOGD("Unhandled key event: No fallback key.");
@@ -4078,7 +3505,6 @@
     dumpDispatchStateLocked(dump);
 
     dump.append(INDENT "Configuration:\n");
-    dump.appendFormat(INDENT2 "MaxEventsPerSecond: %d\n", mConfig.maxEventsPerSecond);
     dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f);
     dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f);
 }
@@ -4086,6 +3512,8 @@
 void InputDispatcher::monitor() {
     // Acquire and release the lock to ensure that the dispatcher has not deadlocked.
     mLock.lock();
+    mLooper->wake();
+    mDispatcherIsAliveCondition.wait(mLock);
     mLock.unlock();
 }
 
@@ -4200,17 +3628,6 @@
 }
 
 
-// --- InputDispatcher::MotionSample ---
-
-InputDispatcher::MotionSample::MotionSample(nsecs_t eventTime,
-        const PointerCoords* pointerCoords, uint32_t pointerCount) :
-        next(NULL), eventTime(eventTime), eventTimeBeforeCoalescing(eventTime) {
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        this->pointerCoords[i].copyFrom(pointerCoords[i]);
-    }
-}
-
-
 // --- InputDispatcher::MotionEntry ---
 
 InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime,
@@ -4220,66 +3637,31 @@
         nsecs_t downTime, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) :
         EventEntry(TYPE_MOTION, eventTime, policyFlags),
+        eventTime(eventTime),
         deviceId(deviceId), source(source), action(action), flags(flags),
         metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags),
         xPrecision(xPrecision), yPrecision(yPrecision),
-        downTime(downTime), pointerCount(pointerCount),
-        firstSample(eventTime, pointerCoords, pointerCount),
-        lastSample(&firstSample) {
+        downTime(downTime), pointerCount(pointerCount) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
+        this->pointerCoords[i].copyFrom(pointerCoords[i]);
     }
 }
 
 InputDispatcher::MotionEntry::~MotionEntry() {
-    for (MotionSample* sample = firstSample.next; sample != NULL; ) {
-        MotionSample* next = sample->next;
-        delete sample;
-        sample = next;
-    }
-}
-
-uint32_t InputDispatcher::MotionEntry::countSamples() const {
-    uint32_t count = 1;
-    for (MotionSample* sample = firstSample.next; sample != NULL; sample = sample->next) {
-        count += 1;
-    }
-    return count;
-}
-
-bool InputDispatcher::MotionEntry::canAppendSamples(int32_t action, uint32_t pointerCount,
-        const PointerProperties* pointerProperties) const {
-    if (this->action != action
-            || this->pointerCount != pointerCount
-            || this->isInjected()) {
-        return false;
-    }
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        if (this->pointerProperties[i] != pointerProperties[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-void InputDispatcher::MotionEntry::appendSample(
-        nsecs_t eventTime, const PointerCoords* pointerCoords) {
-    MotionSample* sample = new MotionSample(eventTime, pointerCoords, pointerCount);
-
-    lastSample->next = sample;
-    lastSample = sample;
 }
 
 
 // --- InputDispatcher::DispatchEntry ---
 
+volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic;
+
 InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry,
         int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) :
+        seq(nextSeq()),
         eventEntry(eventEntry), targetFlags(targetFlags),
         xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor),
-        inProgress(false),
-        resolvedAction(0), resolvedFlags(0),
-        headMotionSample(NULL), tailMotionSample(NULL) {
+        resolvedAction(0), resolvedFlags(0) {
     eventEntry->refCount += 1;
 }
 
@@ -4287,6 +3669,15 @@
     eventEntry->release();
 }
 
+uint32_t InputDispatcher::DispatchEntry::nextSeq() {
+    // Sequence number 0 is reserved and will never be returned.
+    uint32_t seq;
+    do {
+        seq = android_atomic_inc(&sNextSeqAtomic);
+    } while (!seq);
+    return seq;
+}
+
 
 // --- InputDispatcher::InputState ---
 
@@ -4497,7 +3888,7 @@
     pointerCount = entry->pointerCount;
     for (uint32_t i = 0; i < entry->pointerCount; i++) {
         pointerProperties[i].copyFrom(entry->pointerProperties[i]);
-        pointerCoords[i].copyFrom(entry->lastSample->pointerCoords[i]);
+        pointerCoords[i].copyFrom(entry->pointerCoords[i]);
     }
 }
 
@@ -4617,17 +4008,12 @@
         const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
         status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
         monitor(monitor),
-        inputPublisher(inputChannel),
-        lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
+        inputPublisher(inputChannel), inputPublisherBlocked(false) {
 }
 
 InputDispatcher::Connection::~Connection() {
 }
 
-status_t InputDispatcher::Connection::initialize() {
-    return inputPublisher.initialize();
-}
-
 const char* InputDispatcher::Connection::getStatusLabel() const {
     switch (status) {
     case STATUS_NORMAL:
@@ -4644,12 +4030,10 @@
     }
 }
 
-InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent(
-        const EventEntry* eventEntry) const {
-    for (DispatchEntry* dispatchEntry = outboundQueue.tail; dispatchEntry;
-            dispatchEntry = dispatchEntry->prev) {
-        if (dispatchEntry->eventEntry == eventEntry) {
-            return dispatchEntry;
+InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
+    for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) {
+        if (entry->seq == seq) {
+            return entry;
         }
     }
     return NULL;
@@ -4659,7 +4043,8 @@
 // --- InputDispatcher::CommandEntry ---
 
 InputDispatcher::CommandEntry::CommandEntry(Command command) :
-    command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), handled(false) {
+    command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0),
+    seq(0), handled(false) {
 }
 
 InputDispatcher::CommandEntry::~CommandEntry() {
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 1478d67..5c517f51 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -27,6 +27,7 @@
 #include <utils/String8.h>
 #include <utils/Looper.h>
 #include <utils/BitSet.h>
+#include <cutils/atomic.h>
 
 #include <stddef.h>
 #include <unistd.h>
@@ -172,15 +173,9 @@
     // The key repeat inter-key delay.
     nsecs_t keyRepeatDelay;
 
-    // The maximum suggested event delivery rate per second.
-    // This value is used to throttle motion event movement actions on a per-device
-    // basis.  It is not intended to be a hard limit.
-    int32_t maxEventsPerSecond;
-
     InputDispatcherConfiguration() :
             keyRepeatTimeout(500 * 1000000LL),
-            keyRepeatDelay(50 * 1000000LL),
-            maxEventsPerSecond(60) { }
+            keyRepeatDelay(50 * 1000000LL) { }
 };
 
 
@@ -404,6 +399,9 @@
     struct Link {
         T* next;
         T* prev;
+
+    protected:
+        inline Link() : next(NULL), prev(NULL) { }
     };
 
     struct InjectionState {
@@ -496,18 +494,8 @@
         virtual ~KeyEntry();
     };
 
-    struct MotionSample {
-        MotionSample* next;
-
-        nsecs_t eventTime; // may be updated during coalescing
-        nsecs_t eventTimeBeforeCoalescing; // not updated during coalescing
-        PointerCoords pointerCoords[MAX_POINTERS];
-
-        MotionSample(nsecs_t eventTime, const PointerCoords* pointerCoords,
-                uint32_t pointerCount);
-    };
-
     struct MotionEntry : EventEntry {
+        nsecs_t eventTime;
         int32_t deviceId;
         uint32_t source;
         int32_t action;
@@ -520,10 +508,7 @@
         nsecs_t downTime;
         uint32_t pointerCount;
         PointerProperties pointerProperties[MAX_POINTERS];
-
-        // Linked list of motion samples associated with this motion event.
-        MotionSample firstSample;
-        MotionSample* lastSample;
+        PointerCoords pointerCoords[MAX_POINTERS];
 
         MotionEntry(nsecs_t eventTime,
                 int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
@@ -532,46 +517,24 @@
                 nsecs_t downTime, uint32_t pointerCount,
                 const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
 
-        uint32_t countSamples() const;
-
-        // Checks whether we can append samples, assuming the device id and source are the same.
-        bool canAppendSamples(int32_t action, uint32_t pointerCount,
-                const PointerProperties* pointerProperties) const;
-
-        void appendSample(nsecs_t eventTime, const PointerCoords* pointerCoords);
-
     protected:
         virtual ~MotionEntry();
     };
 
     // Tracks the progress of dispatching a particular event to a particular connection.
     struct DispatchEntry : Link<DispatchEntry> {
+        const uint32_t seq; // unique sequence number, never 0
+
         EventEntry* eventEntry; // the event to dispatch
         int32_t targetFlags;
         float xOffset;
         float yOffset;
         float scaleFactor;
 
-        // True if dispatch has started.
-        bool inProgress;
-
         // Set to the resolved action and flags when the event is enqueued.
         int32_t resolvedAction;
         int32_t resolvedFlags;
 
-        // For motion events:
-        //   Pointer to the first motion sample to dispatch in this cycle.
-        //   Usually NULL to indicate that the list of motion samples begins at
-        //   MotionEntry::firstSample.  Otherwise, some samples were dispatched in a previous
-        //   cycle and this pointer indicates the location of the first remainining sample
-        //   to dispatch during the current cycle.
-        MotionSample* headMotionSample;
-        //   Pointer to a motion sample to dispatch in the next cycle if the dispatcher was
-        //   unable to send all motion samples during this cycle.  On the next cycle,
-        //   headMotionSample will be initialized to tailMotionSample and tailMotionSample
-        //   will be set to NULL.
-        MotionSample* tailMotionSample;
-
         DispatchEntry(EventEntry* eventEntry,
                 int32_t targetFlags, float xOffset, float yOffset, float scaleFactor);
         ~DispatchEntry();
@@ -583,6 +546,11 @@
         inline bool isSplit() const {
             return targetFlags & InputTarget::FLAG_SPLIT;
         }
+
+    private:
+        static volatile int32_t sNextSeqAtomic;
+
+        static uint32_t nextSeq();
     };
 
     // A command entry captures state and behavior for an action to be performed in the
@@ -618,6 +586,7 @@
         sp<InputApplicationHandle> inputApplicationHandle;
         sp<InputWindowHandle> inputWindowHandle;
         int32_t userActivityEventType;
+        uint32_t seq;
         bool handled;
     };
 
@@ -819,10 +788,17 @@
         bool monitor;
         InputPublisher inputPublisher;
         InputState inputState;
+
+        // True if the socket is full and no further events can be published until
+        // the application consumes some of the input.
+        bool inputPublisherBlocked;
+
+        // Queue of events that need to be published to the connection.
         Queue<DispatchEntry> outboundQueue;
 
-        nsecs_t lastEventTime; // the time when the event was originally captured
-        nsecs_t lastDispatchTime; // the time when the last event was dispatched
+        // Queue of events that have been published to the connection but that have not
+        // yet received a "finished" response from the application.
+        Queue<DispatchEntry> waitQueue;
 
         explicit Connection(const sp<InputChannel>& inputChannel,
                 const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
@@ -831,21 +807,7 @@
 
         const char* getStatusLabel() const;
 
-        // Finds a DispatchEntry in the outbound queue associated with the specified event.
-        // Returns NULL if not found.
-        DispatchEntry* findQueuedDispatchEntryForEvent(const EventEntry* eventEntry) const;
-
-        // Gets the time since the current event was originally obtained from the input driver.
-        inline double getEventLatencyMillis(nsecs_t currentTime) const {
-            return (currentTime - lastEventTime) / 1000000.0;
-        }
-
-        // Gets the time since the current event entered the outbound dispatch queue.
-        inline double getDispatchLatencyMillis(nsecs_t currentTime) const {
-            return (currentTime - lastDispatchTime) / 1000000.0;
-        }
-
-        status_t initialize();
+        DispatchEntry* findWaitQueueEntry(uint32_t seq);
     };
 
     enum DropReason {
@@ -862,21 +824,15 @@
 
     Mutex mLock;
 
+    Condition mDispatcherIsAliveCondition;
+
     sp<Looper> mLooper;
 
     EventEntry* mPendingEvent;
     Queue<EventEntry> mInboundQueue;
     Queue<CommandEntry> mCommandQueue;
 
-    Vector<EventEntry*> mTempCancelationEvents;
-
     void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
-    void dispatchIdleLocked();
-
-    // Batches a new sample onto a motion entry.
-    // Assumes that the we have already checked that we can append samples.
-    void batchMotionLocked(MotionEntry* entry, nsecs_t eventTime, int32_t metaState,
-            const PointerCoords* pointerCoords, const char* eventDescription);
 
     // Enqueues an inbound event.  Returns true if mLooper->wake() should be called.
     bool enqueueInboundEventLocked(EventEntry* entry);
@@ -902,17 +858,11 @@
 
     sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y);
 
-    // All registered connections mapped by receive pipe file descriptor.
-    KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
+    // All registered connections mapped by channel file descriptor.
+    KeyedVector<int, sp<Connection> > mConnectionsByFd;
 
     ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
 
-    // Active connections are connections that have a non-empty outbound queue.
-    // We don't use a ref-counted pointer here because we explicitly abort connections
-    // during unregistration which causes the connection's outbound queue to be cleared
-    // and the connection itself to be deactivated.
-    Vector<Connection*> mActiveConnections;
-
     // Input channels that will receive a copy of all input events.
     Vector<sp<InputChannel> > mMonitoringChannels;
 
@@ -925,17 +875,6 @@
     void incrementPendingForegroundDispatchesLocked(EventEntry* entry);
     void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
 
-    // Throttling state.
-    struct ThrottleState {
-        nsecs_t minTimeBetweenEvents;
-
-        nsecs_t lastEventTime;
-        int32_t lastDeviceId;
-        uint32_t lastSource;
-
-        uint32_t originalSampleCount; // only collected during debugging
-    } mThrottleState;
-
     // Key repeat tracking.
     struct KeyRepeatState {
         KeyEntry* lastKeyEntry; // or null if no repeat
@@ -1008,16 +947,13 @@
     bool dispatchMotionLocked(
             nsecs_t currentTime, MotionEntry* entry,
             DropReason* dropReason, nsecs_t* nextWakeupTime);
-    void dispatchEventToCurrentInputTargetsLocked(
-            nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
+    void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
+            const Vector<InputTarget>& inputTargets);
 
     void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry);
     void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry);
 
-    // The input targets that were most recently identified for dispatch.
-    bool mCurrentInputTargetsValid; // false while targets are being recomputed
-    Vector<InputTarget> mCurrentInputTargets;
-
+    // Keeping track of ANR timeouts.
     enum InputTargetWaitCause {
         INPUT_TARGET_WAIT_CAUSE_NONE,
         INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY,
@@ -1034,8 +970,6 @@
     sp<InputWindowHandle> mLastHoverWindowHandle;
 
     // Finding targets for input events.
-    void resetTargetsLocked();
-    void commitTargetsLocked();
     int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
             const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle,
@@ -1046,20 +980,22 @@
     void resetANRTimeoutsLocked();
 
     int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
-            nsecs_t* nextWakeupTime);
+            Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime);
     int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
-            nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
-            const MotionSample** outSplitBatchAfterSample);
+            Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+            bool* outConflictingPointerActions);
 
     void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
-            int32_t targetFlags, BitSet32 pointerIds);
-    void addMonitoringTargetsLocked();
+            int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
+    void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets);
+
     void pokeUserActivityLocked(const EventEntry* eventEntry);
     bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
             const InjectionState* injectionState);
     bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
             int32_t x, int32_t y) const;
-    bool isWindowFinishedWithPreviousInputLocked(const sp<InputWindowHandle>& windowHandle);
+    bool isWindowReadyForMoreInputLocked(nsecs_t currentTime,
+            const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry);
     String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle);
 
@@ -1068,22 +1004,19 @@
     // with the mutex held makes it easier to ensure that connection invariants are maintained.
     // If needed, the methods post commands to run later once the critical bits are done.
     void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget,
-            bool resumeWithAppendedMotionSample);
+            EventEntry* eventEntry, const InputTarget* inputTarget);
     void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget,
-            bool resumeWithAppendedMotionSample);
+            EventEntry* eventEntry, const InputTarget* inputTarget);
     void enqueueDispatchEntryLocked(const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget,
-            bool resumeWithAppendedMotionSample, int32_t dispatchMode);
+            EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
     void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
     void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-            bool handled);
-    void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+            uint32_t seq, bool handled);
     void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
             bool notify);
-    void drainOutboundQueueLocked(Connection* connection);
-    static int handleReceiveCallback(int receiveFd, int events, void* data);
+    void drainDispatchQueueLocked(Queue<DispatchEntry>* queue);
+    void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry);
+    static int handleReceiveCallback(int fd, int events, void* data);
 
     void synthesizeCancelationEventsForAllConnectionsLocked(
             const CancelationOptions& options);
@@ -1111,10 +1044,8 @@
     void deactivateConnectionLocked(Connection* connection);
 
     // Interesting events that we might like to log or tell the framework about.
-    void onDispatchCycleStartedLocked(
-            nsecs_t currentTime, const sp<Connection>& connection);
     void onDispatchCycleFinishedLocked(
-            nsecs_t currentTime, const sp<Connection>& connection, bool handled);
+            nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
     void onDispatchCycleBrokenLocked(
             nsecs_t currentTime, const sp<Connection>& connection);
     void onANRLocked(
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index fa0b3d8..4be06e4 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -278,17 +278,20 @@
 
     { // acquire lock
         AutoMutex _l(mLock);
+        mReaderIsAliveCondition.broadcast();
 
         if (count) {
             processEventsLocked(mEventBuffer, count);
         }
         if (!count || timeoutMillis == 0) {
             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+            if (now >= mNextTimeout) {
 #if DEBUG_RAW_EVENTS
-            ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
+                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
 #endif
-            mNextTimeout = LLONG_MAX;
-            timeoutExpiredLocked(now);
+                mNextTimeout = LLONG_MAX;
+                timeoutExpiredLocked(now);
+            }
         }
     } // release lock
 
@@ -772,6 +775,8 @@
 void InputReader::monitor() {
     // Acquire and release the lock to ensure that the reader has not deadlocked.
     mLock.lock();
+    mEventHub->wake();
+    mReaderIsAliveCondition.wait(mLock);
     mLock.unlock();
 
     // Check the EventHub
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index a122c97..ad89a22 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -363,6 +363,8 @@
 private:
     Mutex mLock;
 
+    Condition mReaderIsAliveCondition;
+
     sp<EventHubInterface> mEventHub;
     sp<InputReaderPolicyInterface> mPolicy;
     sp<QueuedInputListener> mQueuedListener;
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 4f81178..081f1f4 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -24,67 +24,35 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.Intent.FilterComparison;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.net.Uri;
 import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
-import android.util.TypedValue;
-import android.util.Xml;
+import android.util.SparseArray;
 import android.widget.RemoteViews;
 
 import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.os.AtomicFile;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.widget.IRemoteViewsAdapterConnection;
-import com.android.internal.widget.IRemoteViewsFactory;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
-import java.util.Set;
 
+
+/**
+ * Redirects calls to this service to the instance of the service for the appropriate user.
+ */
 class AppWidgetService extends IAppWidgetService.Stub
 {
     private static final String TAG = "AppWidgetService";
 
-    private static final String SETTINGS_FILENAME = "appwidgets.xml";
-    private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
-
     /*
      * When identifying a Host or Provider based on the calling process, use the uid field.
      * When identifying a Host or Provider based on a package manager broadcast, use the
@@ -125,11 +93,9 @@
      * globally and may lead us to leak AppWidgetService instances (if there were more than one).
      */
     static class ServiceConnectionProxy implements ServiceConnection {
-        private final Pair<Integer, Intent.FilterComparison> mKey;
         private final IBinder mConnectionCb;
 
         ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
-            mKey = key;
             mConnectionCb = connectionCb;
         }
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -155,13 +121,6 @@
         }
     }
 
-    // Manages active connections to RemoteViewsServices
-    private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection>
-        mBoundRemoteViewsServices = new HashMap<Pair<Integer,FilterComparison>,ServiceConnection>();
-    // Manages persistent references to RemoteViewsServices from different App Widgets
-    private final HashMap<FilterComparison, HashSet<Integer>>
-        mRemoteViewsServicesAppWidgets = new HashMap<FilterComparison, HashSet<Integer>>();
-
     Context mContext;
     Locale mLocale;
     PackageManager mPackageManager;
@@ -171,35 +130,32 @@
     final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
     ArrayList<Host> mHosts = new ArrayList<Host>();
     boolean mSafeMode;
-    boolean mStateLoaded;
 
-    // These are for debugging only -- widgets are going missing in some rare instances
-    ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>();
-    ArrayList<Host> mDeletedHosts = new ArrayList<Host>();
+
+    private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
 
     AppWidgetService(Context context) {
         mContext = context;
-        mPackageManager = context.getPackageManager();
-        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
+        AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0);
+        mAppWidgetServices.append(0, primary);
     }
 
     public void systemReady(boolean safeMode) {
         mSafeMode = safeMode;
 
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-        }
+        mAppWidgetServices.get(0).systemReady(safeMode);
 
         // Register for the boot completed broadcast, so we can send the
-        // ENABLE broacasts.  If we try to send them now, they time out,
+        // ENABLE broacasts. If we try to send them now, they time out,
         // because the system isn't ready to handle them yet.
         mContext.registerReceiver(mBroadcastReceiver,
                 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
 
         // Register for configuration changes so we can update the names
         // of the widgets when the locale changes.
-        mContext.registerReceiver(mBroadcastReceiver,
-                new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
+        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(
+                Intent.ACTION_CONFIGURATION_CHANGED), null, null);
 
         // Register for broadcasts about package install, etc., so we can
         // update the provider list.
@@ -216,216 +172,24 @@
         mContext.registerReceiver(mBroadcastReceiver, sdFilter);
     }
 
-    private void ensureStateLoadedLocked() {
-        if (!mStateLoaded) {
-            loadAppWidgetList();
-            loadStateLocked();
-            mStateLoaded = true;
-        }
+    @Override
+    public int allocateAppWidgetId(String packageName, int hostId) throws RemoteException {
+        return getImplForUser().allocateAppWidgetId(packageName, hostId);
     }
-
-    private void dumpProvider(Provider p, int index, PrintWriter pw) {
-        AppWidgetProviderInfo info = p.info;
-        pw.print("  ["); pw.print(index); pw.print("] provider ");
-                pw.print(info.provider.flattenToShortString());
-                pw.println(':');
-        pw.print("    min=("); pw.print(info.minWidth);
-                pw.print("x"); pw.print(info.minHeight);
-        pw.print(")   minResize=("); pw.print(info.minResizeWidth);
-                pw.print("x"); pw.print(info.minResizeHeight);
-                pw.print(") updatePeriodMillis=");
-                pw.print(info.updatePeriodMillis);
-                pw.print(" resizeMode=");
-                pw.print(info.resizeMode);
-                pw.print(" autoAdvanceViewId=");
-                pw.print(info.autoAdvanceViewId);
-                pw.print(" initialLayout=#");
-                pw.print(Integer.toHexString(info.initialLayout));
-                pw.print(" zombie="); pw.println(p.zombie);
-    }
-
-    private void dumpHost(Host host, int index, PrintWriter pw) {
-        pw.print("  ["); pw.print(index); pw.print("] hostId=");
-                pw.print(host.hostId); pw.print(' ');
-                pw.print(host.packageName); pw.print('/');
-        pw.print(host.uid); pw.println(':');
-        pw.print("    callbacks="); pw.println(host.callbacks);
-        pw.print("    instances.size="); pw.print(host.instances.size());
-                pw.print(" zombie="); pw.println(host.zombie);
-    }
-
-    private void dumpAppWidgetId(AppWidgetId id, int index, PrintWriter pw) {
-        pw.print("  ["); pw.print(index); pw.print("] id=");
-                pw.println(id.appWidgetId);
-        pw.print("    hostId=");
-                pw.print(id.host.hostId); pw.print(' ');
-                pw.print(id.host.packageName); pw.print('/');
-                pw.println(id.host.uid);
-        if (id.provider != null) {
-            pw.print("    provider=");
-                    pw.println(id.provider.info.provider.flattenToShortString());
-        }
-        if (id.host != null) {
-            pw.print("    host.callbacks="); pw.println(id.host.callbacks);
-        }
-        if (id.views != null) {
-            pw.print("    views="); pw.println(id.views);
-        }
+    
+    @Override
+    public void deleteAppWidgetId(int appWidgetId) throws RemoteException {
+        getImplForUser().deleteAppWidgetId(appWidgetId);
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        synchronized (mAppWidgetIds) {
-            int N = mInstalledProviders.size();
-            pw.println("Providers:");
-            for (int i=0; i<N; i++) {
-                dumpProvider(mInstalledProviders.get(i), i, pw);
-            }
-
-            N = mAppWidgetIds.size();
-            pw.println(" ");
-            pw.println("AppWidgetIds:");
-            for (int i=0; i<N; i++) {
-                dumpAppWidgetId(mAppWidgetIds.get(i), i, pw);
-            }
-
-            N = mHosts.size();
-            pw.println(" ");
-            pw.println("Hosts:");
-            for (int i=0; i<N; i++) {
-                dumpHost(mHosts.get(i), i, pw);
-            }
-
-            N = mDeletedProviders.size();
-            pw.println(" ");
-            pw.println("Deleted Providers:");
-            for (int i=0; i<N; i++) {
-                dumpProvider(mDeletedProviders.get(i), i, pw);
-            }
-
-            N = mDeletedHosts.size();
-            pw.println(" ");
-            pw.println("Deleted Hosts:");
-            for (int i=0; i<N; i++) {
-                dumpHost(mDeletedHosts.get(i), i, pw);
-            }
-        }
+    public void deleteHost(int hostId) throws RemoteException {
+        getImplForUser().deleteHost(hostId);
     }
 
-    public int allocateAppWidgetId(String packageName, int hostId) {
-        int callingUid = enforceCallingUid(packageName);
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            int appWidgetId = mNextAppWidgetId++;
-
-            Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
-
-            AppWidgetId id = new AppWidgetId();
-            id.appWidgetId = appWidgetId;
-            id.host = host;
-
-            host.instances.add(id);
-            mAppWidgetIds.add(id);
-
-            saveStateLocked();
-
-            return appWidgetId;
-        }
-    }
-
-    public void deleteAppWidgetId(int appWidgetId) {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
-            if (id != null) {
-                deleteAppWidgetLocked(id);
-                saveStateLocked();
-            }
-        }
-    }
-
-    public void deleteHost(int hostId) {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            int callingUid = getCallingUid();
-            Host host = lookupHostLocked(callingUid, hostId);
-            if (host != null) {
-                deleteHostLocked(host);
-                saveStateLocked();
-            }
-        }
-    }
-
-    public void deleteAllHosts() {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            int callingUid = getCallingUid();
-            final int N = mHosts.size();
-            boolean changed = false;
-            for (int i=N-1; i>=0; i--) {
-                Host host = mHosts.get(i);
-                if (host.uid == callingUid) {
-                    deleteHostLocked(host);
-                    changed = true;
-                }
-            }
-            if (changed) {
-                saveStateLocked();
-            }
-        }
-    }
-
-    void deleteHostLocked(Host host) {
-        final int N = host.instances.size();
-        for (int i=N-1; i>=0; i--) {
-            AppWidgetId id = host.instances.get(i);
-            deleteAppWidgetLocked(id);
-        }
-        host.instances.clear();
-        mHosts.remove(host);
-        mDeletedHosts.add(host);
-        // it's gone or going away, abruptly drop the callback connection
-        host.callbacks = null;
-    }
-
-    void deleteAppWidgetLocked(AppWidgetId id) {
-        // We first unbind all services that are bound to this id
-        unbindAppWidgetRemoteViewsServicesLocked(id);
-
-        Host host = id.host;
-        host.instances.remove(id);
-        pruneHostLocked(host);
-
-        mAppWidgetIds.remove(id);
-
-        Provider p = id.provider;
-        if (p != null) {
-            p.instances.remove(id);
-            if (!p.zombie) {
-                // send the broacast saying that this appWidgetId has been deleted
-                Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
-                intent.setComponent(p.info.provider);
-                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
-                mContext.sendBroadcast(intent);
-                if (p.instances.size() == 0) {
-                    // cancel the future updates
-                    cancelBroadcasts(p);
-
-                    // send the broacast saying that the provider is not in use any more
-                    intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
-                    intent.setComponent(p.info.provider);
-                    mContext.sendBroadcast(intent);
-                }
-            }
-        }
+    @Override
+    public void deleteAllHosts() throws RemoteException {
+        getImplForUser().deleteAllHosts();
     }
 
     void cancelBroadcasts(Provider p) {
@@ -441,617 +205,58 @@
         }
     }
 
-    public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
-        mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
-                "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider);
-        
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mAppWidgetIds) {
-                ensureStateLoadedLocked();
-                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
-                if (id == null) {
-                    throw new IllegalArgumentException("bad appWidgetId");
-                }
-                if (id.provider != null) {
-                    throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to "
-                            + id.provider.info.provider);
-                }
-                Provider p = lookupProviderLocked(provider);
-                if (p == null) {
-                    throw new IllegalArgumentException("not a appwidget provider: " + provider);
-                }
-                if (p.zombie) {
-                    throw new IllegalArgumentException("can't bind to a 3rd party provider in"
-                            + " safe mode: " + provider);
-                }
-    
-                id.provider = p;
-                p.instances.add(id);
-                int instancesSize = p.instances.size();
-                if (instancesSize == 1) {
-                    // tell the provider that it's ready
-                    sendEnableIntentLocked(p);
-                }
-    
-                // send an update now -- We need this update now, and just for this appWidgetId.
-                // It's less critical when the next one happens, so when we schdule the next one,
-                // we add updatePeriodMillis to its start time.  That time will have some slop,
-                // but that's okay.
-                sendUpdateIntentLocked(p, new int[] { appWidgetId });
-    
-                // schedule the future updates
-                registerForBroadcastsLocked(p, getAppWidgetIds(p));
-                saveStateLocked();
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
+    @Override
+    public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException {
+        getImplForUser().bindAppWidgetId(appWidgetId, provider);
     }
 
-    // Binds to a specific RemoteViewsService
-    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
-            if (id == null) {
-                throw new IllegalArgumentException("bad appWidgetId");
-            }
-            final ComponentName componentName = intent.getComponent();
-            try {
-                final ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName,
-                        PackageManager.GET_PERMISSIONS);
-                if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(si.permission)) {
-                    throw new SecurityException("Selected service does not require "
-                            + android.Manifest.permission.BIND_REMOTEVIEWS
-                            + ": " + componentName);
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                throw new IllegalArgumentException("Unknown component " + componentName);
-            }
-
-            // If there is already a connection made for this service intent, then disconnect from
-            // that first.  (This does not allow multiple connections to the same service under
-            // the same key)
-            ServiceConnectionProxy conn = null;
-            FilterComparison fc = new FilterComparison(intent);
-            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc);
-            if (mBoundRemoteViewsServices.containsKey(key)) {
-                conn = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key);
-                conn.disconnect();
-                mContext.unbindService(conn);
-                mBoundRemoteViewsServices.remove(key);
-            }
-
-            // Bind to the RemoteViewsService (which will trigger a callback to the
-            // RemoteViewsAdapter.onServiceConnected())
-            final long token = Binder.clearCallingIdentity();
-            try {
-                conn = new ServiceConnectionProxy(key, connection);
-                mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
-                mBoundRemoteViewsServices.put(key, conn);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-
-            // Add it to the mapping of RemoteViewsService to appWidgetIds so that we can determine
-            // when we can call back to the RemoteViewsService later to destroy associated
-            // factories.
-            incrementAppWidgetServiceRefCount(appWidgetId, fc);
-        }
+    @Override
+    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection)
+            throws RemoteException {
+        getImplForUser().bindRemoteViewsService(appWidgetId, intent, connection);
     }
 
-    // Unbinds from a specific RemoteViewsService
-    public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            // Unbind from the RemoteViewsService (which will trigger a callback to the bound
-            // RemoteViewsAdapter)
-            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
-                    new FilterComparison(intent));
-            if (mBoundRemoteViewsServices.containsKey(key)) {
-                // We don't need to use the appWidgetId until after we are sure there is something
-                // to unbind.  Note that this may mask certain issues with apps calling unbind()
-                // more than necessary.
-                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
-                if (id == null) {
-                    throw new IllegalArgumentException("bad appWidgetId");
-                }
-
-                ServiceConnectionProxy conn =
-                    (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key);
-                conn.disconnect();
-                mContext.unbindService(conn);
-                mBoundRemoteViewsServices.remove(key);
-            } else {
-                Log.e("AppWidgetService", "Error (unbindRemoteViewsService): Connection not bound");
-            }
-        }
+    @Override
+    public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
+            List<RemoteViews> updatedViews) throws RemoteException {
+        return getImplForUser().startListening(host, packageName, hostId, updatedViews);
     }
 
-    // Unbinds from a RemoteViewsService when we delete an app widget
-    private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) {
-        int appWidgetId = id.appWidgetId;
-        // Unbind all connections to Services bound to this AppWidgetId
-        Iterator<Pair<Integer, Intent.FilterComparison>> it =
-            mBoundRemoteViewsServices.keySet().iterator();
-        while (it.hasNext()) {
-            final Pair<Integer, Intent.FilterComparison> key = it.next();
-            if (key.first.intValue() == appWidgetId) {
-                final ServiceConnectionProxy conn = (ServiceConnectionProxy)
-                        mBoundRemoteViewsServices.get(key);
-                conn.disconnect();
-                mContext.unbindService(conn);
-                it.remove();
-            }
-        }
-
-        // Check if we need to destroy any services (if no other app widgets are
-        // referencing the same service)
-        decrementAppWidgetServiceRefCount(appWidgetId);
+    // TODO: Call this from PackageManagerService when a user is removed
+    public void removeUser(int userId) {
     }
 
-    // Destroys the cached factory on the RemoteViewsService's side related to the specified intent
-    private void destroyRemoteViewsService(final Intent intent) {
-        final ServiceConnection conn = new ServiceConnection() {
-            @Override
-            public void onServiceConnected(ComponentName name, IBinder service) {
-                final IRemoteViewsFactory cb =
-                    IRemoteViewsFactory.Stub.asInterface(service);
-                try {
-                    cb.onDestroy(intent);
-                } catch (RemoteException e) {
-                    e.printStackTrace();
-                } catch (RuntimeException e) {
-                    e.printStackTrace();
-                }
-                mContext.unbindService(this);
-            }
-            @Override
-            public void onServiceDisconnected(android.content.ComponentName name) {
-                // Do nothing
-            }
-        };
-
-        // Bind to the service and remove the static intent->factory mapping in the
-        // RemoteViewsService.
-        final long token = Binder.clearCallingIdentity();
-        try {
-            mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
-        } finally {
-            Binder.restoreCallingIdentity(token);
+    private AppWidgetServiceImpl getImplForUser() {
+        final int userId = Binder.getOrigCallingUser();
+        AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
+        if (service == null) {
+            Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
+            // TODO: Verify that it's a valid user
+            service = new AppWidgetServiceImpl(mContext, userId);
+            service.systemReady(mSafeMode);
+            // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
+            service.sendInitialBroadcasts();
+            mAppWidgetServices.append(userId, service);
         }
+
+        return service;
     }
 
-    // Adds to the ref-count for a given RemoteViewsService intent
-    private void incrementAppWidgetServiceRefCount(int appWidgetId, FilterComparison fc) {
-        HashSet<Integer> appWidgetIds = null;
-        if (mRemoteViewsServicesAppWidgets.containsKey(fc)) {
-            appWidgetIds = mRemoteViewsServicesAppWidgets.get(fc);
-        } else {
-            appWidgetIds = new HashSet<Integer>();
-            mRemoteViewsServicesAppWidgets.put(fc, appWidgetIds);
-        }
-        appWidgetIds.add(appWidgetId);
+    @Override
+    public int[] getAppWidgetIds(ComponentName provider) throws RemoteException {
+        return getImplForUser().getAppWidgetIds(provider);
     }
 
-    // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
-    // the ref-count reaches zero.
-    private void decrementAppWidgetServiceRefCount(int appWidgetId) {
-        Iterator<FilterComparison> it =
-            mRemoteViewsServicesAppWidgets.keySet().iterator();
-        while (it.hasNext()) {
-            final FilterComparison key = it.next();
-            final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
-            if (ids.remove(appWidgetId)) {
-                // If we have removed the last app widget referencing this service, then we
-                // should destroy it and remove it from this set
-                if (ids.isEmpty()) {
-                    destroyRemoteViewsService(key.getIntent());
-                    it.remove();
-                }
-            }
-        }
+    @Override
+    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) throws RemoteException {
+        return getImplForUser().getAppWidgetInfo(appWidgetId);
     }
 
-    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
-            if (id != null && id.provider != null && !id.provider.zombie) {
-                return id.provider.info;
-            }
-            return null;
-        }
+    @Override
+    public RemoteViews getAppWidgetViews(int appWidgetId) throws RemoteException {
+        return getImplForUser().getAppWidgetViews(appWidgetId);
     }
 
-    public RemoteViews getAppWidgetViews(int appWidgetId) {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
-            if (id != null) {
-                return id.views;
-            }
-            return null;
-        }
-    }
-
-    public List<AppWidgetProviderInfo> getInstalledProviders() {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            final int N = mInstalledProviders.size();
-            ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
-            for (int i=0; i<N; i++) {
-                Provider p = mInstalledProviders.get(i);
-                if (!p.zombie) {
-                    result.add(p.info);
-                }
-            }
-            return result;
-        }
-    }
-
-    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
-        if (appWidgetIds == null) {
-            return;
-        }
-        if (appWidgetIds.length == 0) {
-            return;
-        }
-        final int N = appWidgetIds.length;
-
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            for (int i=0; i<N; i++) {
-                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
-                updateAppWidgetInstanceLocked(id, views);
-            }
-        }
-    }
-
-    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
-        if (appWidgetIds == null) {
-            return;
-        }
-        if (appWidgetIds.length == 0) {
-            return;
-        }
-        final int N = appWidgetIds.length;
-
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            for (int i=0; i<N; i++) {
-                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
-                updateAppWidgetInstanceLocked(id, views, true);
-            }
-        }
-    }
-
-    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
-        if (appWidgetIds == null) {
-            return;
-        }
-        if (appWidgetIds.length == 0) {
-            return;
-        }
-        final int N = appWidgetIds.length;
-
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            for (int i=0; i<N; i++) {
-                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
-                notifyAppWidgetViewDataChangedInstanceLocked(id, viewId);
-            }
-        }
-    }
-
-    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            Provider p = lookupProviderLocked(provider);
-            if (p == null) {
-                Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider);
-                return;
-            }
-            ArrayList<AppWidgetId> instances = p.instances;
-            final int callingUid = getCallingUid();
-            final int N = instances.size();
-            for (int i=0; i<N; i++) {
-                AppWidgetId id = instances.get(i);
-                if (canAccessAppWidgetId(id, callingUid)) {
-                    updateAppWidgetInstanceLocked(id, views);
-                }
-            }
-        }
-    }
-
-    void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) {
-        updateAppWidgetInstanceLocked(id, views, false);
-    }
-
-    void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate) {
-        // allow for stale appWidgetIds and other badness
-        // lookup also checks that the calling process can access the appWidgetId
-        // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
-        if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
-
-            // We do not want to save this RemoteViews
-            if (!isPartialUpdate) id.views = views;
-
-            // is anyone listening?
-            if (id.host.callbacks != null) {
-                try {
-                    // the lock is held, but this is a oneway call
-                    id.host.callbacks.updateAppWidget(id.appWidgetId, views);
-                } catch (RemoteException e) {
-                    // It failed; remove the callback. No need to prune because
-                    // we know that this host is still referenced by this instance.
-                    id.host.callbacks = null;
-                }
-            }
-        }
-    }
-
-    void notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, int viewId) {
-        // allow for stale appWidgetIds and other badness
-        // lookup also checks that the calling process can access the appWidgetId
-        // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
-        if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
-            // is anyone listening?
-            if (id.host.callbacks != null) {
-                try {
-                    // the lock is held, but this is a oneway call
-                    id.host.callbacks.viewDataChanged(id.appWidgetId, viewId);
-                } catch (RemoteException e) {
-                    // It failed; remove the callback. No need to prune because
-                    // we know that this host is still referenced by this instance.
-                    id.host.callbacks = null;
-                }
-            }
-
-            // If the host is unavailable, then we call the associated
-            // RemoteViewsFactory.onDataSetChanged() directly
-            if (id.host.callbacks == null) {
-                Set<FilterComparison> keys = mRemoteViewsServicesAppWidgets.keySet();
-                for (FilterComparison key : keys) {
-                    if (mRemoteViewsServicesAppWidgets.get(key).contains(id.appWidgetId)) {
-                        Intent intent = key.getIntent();
-
-                        final ServiceConnection conn = new ServiceConnection() {
-                            @Override
-                            public void onServiceConnected(ComponentName name, IBinder service) {
-                                IRemoteViewsFactory cb =
-                                    IRemoteViewsFactory.Stub.asInterface(service);
-                                try {
-                                    cb.onDataSetChangedAsync();
-                                } catch (RemoteException e) {
-                                    e.printStackTrace();
-                                } catch (RuntimeException e) {
-                                    e.printStackTrace();
-                                }
-                                mContext.unbindService(this);
-                            }
-                            @Override
-                            public void onServiceDisconnected(android.content.ComponentName name) {
-                                // Do nothing
-                            }
-                        };
-
-                        // Bind to the service and call onDataSetChanged()
-                        final long token = Binder.clearCallingIdentity();
-                        try {
-                            mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
-                        } finally {
-                            Binder.restoreCallingIdentity(token);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
-            List<RemoteViews> updatedViews) {
-        int callingUid = enforceCallingUid(packageName);
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
-            host.callbacks = callbacks;
-
-            updatedViews.clear();
-
-            ArrayList<AppWidgetId> instances = host.instances;
-            int N = instances.size();
-            int[] updatedIds = new int[N];
-            for (int i=0; i<N; i++) {
-                AppWidgetId id = instances.get(i);
-                updatedIds[i] = id.appWidgetId;
-                updatedViews.add(id.views);
-            }
-            return updatedIds;
-        }
-    }
-
-    public void stopListening(int hostId) {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            Host host = lookupHostLocked(getCallingUid(), hostId);
-            if (host != null) {
-                host.callbacks = null;
-                pruneHostLocked(host);
-            }
-        }
-    }
-
-    boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
-        if (id.host.uid == callingUid) {
-            // Apps hosting the AppWidget have access to it.
-            return true;
-        }
-        if (id.provider != null && id.provider.uid == callingUid) {
-            // Apps providing the AppWidget have access to it (if the appWidgetId has been bound)
-            return true;
-        }
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET)
-                == PackageManager.PERMISSION_GRANTED) {
-            // Apps that can bind have access to all appWidgetIds.
-            return true;
-        }
-        // Nobody else can access it.
-        return false;
-    }
-
-   AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) {
-        int callingUid = getCallingUid();
-        final int N = mAppWidgetIds.size();
-        for (int i=0; i<N; i++) {
-            AppWidgetId id = mAppWidgetIds.get(i);
-            if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) {
-                return id;
-            }
-        }
-        return null;
-    }
-
-    Provider lookupProviderLocked(ComponentName provider) {
-        final int N = mInstalledProviders.size();
-        for (int i=0; i<N; i++) {
-            Provider p = mInstalledProviders.get(i);
-            if (p.info.provider.equals(provider)) {
-                return p;
-            }
-        }
-        return null;
-    }
-
-    Host lookupHostLocked(int uid, int hostId) {
-        final int N = mHosts.size();
-        for (int i=0; i<N; i++) {
-            Host h = mHosts.get(i);
-            if (h.uid == uid && h.hostId == hostId) {
-                return h;
-            }
-        }
-        return null;
-    }
-
-    Host lookupOrAddHostLocked(int uid, String packageName, int hostId) {
-        final int N = mHosts.size();
-        for (int i=0; i<N; i++) {
-            Host h = mHosts.get(i);
-            if (h.hostId == hostId && h.packageName.equals(packageName)) {
-                return h;
-            }
-        }
-        Host host = new Host();
-        host.packageName = packageName;
-        host.uid = uid;
-        host.hostId = hostId;
-        mHosts.add(host);
-        return host;
-    }
-
-    void pruneHostLocked(Host host) {
-        if (host.instances.size() == 0 && host.callbacks == null) {
-            mHosts.remove(host);
-        }
-    }
-
-    void loadAppWidgetList() {
-        PackageManager pm = mPackageManager;
-
-        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
-        List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
-                PackageManager.GET_META_DATA);
-
-        final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
-        for (int i=0; i<N; i++) {
-            ResolveInfo ri = broadcastReceivers.get(i);
-            addProviderLocked(ri);
-        }
-    }
-
-    boolean addProviderLocked(ResolveInfo ri) {
-        if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
-            return false;
-        }
-        if (!ri.activityInfo.isEnabled()) {
-            return false;
-        }
-        Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
-                    ri.activityInfo.name), ri);
-        if (p != null) {
-            mInstalledProviders.add(p);
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    void removeProviderLocked(int index, Provider p) {
-        int N = p.instances.size();
-        for (int i=0; i<N; i++) {
-            AppWidgetId id = p.instances.get(i);
-            // Call back with empty RemoteViews
-            updateAppWidgetInstanceLocked(id, null);
-            // Stop telling the host about updates for this from now on
-            cancelBroadcasts(p);
-            // clear out references to this appWidgetId
-            id.host.instances.remove(id);
-            mAppWidgetIds.remove(id);
-            id.provider = null;
-            pruneHostLocked(id.host);
-            id.host = null;
-        }
-        p.instances.clear();
-        mInstalledProviders.remove(index);
-        mDeletedProviders.add(p);
-        // no need to send the DISABLE broadcast, since the receiver is gone anyway
-        cancelBroadcasts(p);
-    }
-
-    void sendEnableIntentLocked(Provider p) {
-        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
-        intent.setComponent(p.info.provider);
-        mContext.sendBroadcast(intent);
-    }
-
-    void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
-        if (appWidgetIds != null && appWidgetIds.length > 0) {
-            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
-            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
-            intent.setComponent(p.info.provider);
-            mContext.sendBroadcast(intent);
-        }
-    }
-
-    void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) {
-        if (p.info.updatePeriodMillis > 0) {
-            // if this is the first instance, set the alarm.  otherwise,
-            // rely on the fact that we've already set it and that
-            // PendingIntent.getBroadcast will update the extras.
-            boolean alreadyRegistered = p.broadcast != null;
-            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
-            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
-            intent.setComponent(p.info.provider);
-            long token = Binder.clearCallingIdentity();
-            try {
-                p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
-                        PendingIntent.FLAG_UPDATE_CURRENT);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-            if (!alreadyRegistered) {
-                long period = p.info.updatePeriodMillis;
-                if (period < MIN_UPDATE_PERIOD) {
-                    period = MIN_UPDATE_PERIOD;
-                }
-                mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                        SystemClock.elapsedRealtime() + period, period, p.broadcast);
-            }
-        }
-    }
-    
     static int[] getAppWidgetIds(Provider p) {
         int instancesSize = p.instances.size();
         int appWidgetIds[] = new int[instancesSize];
@@ -1060,570 +265,70 @@
         }
         return appWidgetIds;
     }
-    
-    public int[] getAppWidgetIds(ComponentName provider) {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            Provider p = lookupProviderLocked(provider);
-            if (p != null && getCallingUid() == p.uid) {
-                return getAppWidgetIds(p);                
-            } else {
-                return new int[0];
-            }
-        }
+
+    @Override
+    public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
+        return getImplForUser().getInstalledProviders();
     }
 
-    private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
-        Provider p = null;
-
-        ActivityInfo activityInfo = ri.activityInfo;
-        XmlResourceParser parser = null;
-        try {
-            parser = activityInfo.loadXmlMetaData(mPackageManager,
-                    AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
-            if (parser == null) {
-                Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for "
-                        + "AppWidget provider '" + component + '\'');
-                return null;
-            }
-
-            AttributeSet attrs = Xml.asAttributeSet(parser);
-
-            int type;
-            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                    && type != XmlPullParser.START_TAG) {
-                // drain whitespace, comments, etc.
-            }
-
-            String nodeName = parser.getName();
-            if (!"appwidget-provider".equals(nodeName)) {
-                Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
-                        + " AppWidget provider '" + component + '\'');
-                return null;
-            }
-
-            p = new Provider();
-            AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo();
-            info.provider = component;
-            p.uid = activityInfo.applicationInfo.uid;
-
-            Resources res = mPackageManager.getResourcesForApplication(
-                    activityInfo.applicationInfo);
-
-            TypedArray sa = res.obtainAttributes(attrs,
-                    com.android.internal.R.styleable.AppWidgetProviderInfo);
-
-            // These dimensions has to be resolved in the application's context.
-            // We simply send back the raw complex data, which will be
-            // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
-            TypedValue value = sa.peekValue(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
-            info.minWidth = value != null ? value.data : 0; 
-            value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
-            info.minHeight = value != null ? value.data : 0;
-            value = sa.peekValue(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth);
-            info.minResizeWidth = value != null ? value.data : info.minWidth;
-            value = sa.peekValue(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight);
-            info.minResizeHeight = value != null ? value.data : info.minHeight;
-
-            info.updatePeriodMillis = sa.getInt(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
-            info.initialLayout = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
-            String className = sa.getString(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
-            if (className != null) {
-                info.configure = new ComponentName(component.getPackageName(), className);
-            }
-            info.label = activityInfo.loadLabel(mPackageManager).toString();
-            info.icon = ri.getIconResource();
-            info.previewImage = sa.getResourceId(
-            		com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
-            info.autoAdvanceViewId = sa.getResourceId(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
-            info.resizeMode = sa.getInt(
-                    com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
-                    AppWidgetProviderInfo.RESIZE_NONE);
-
-            sa.recycle();
-        } catch (Exception e) {
-            // Ok to catch Exception here, because anything going wrong because
-            // of what a client process passes to us should not be fatal for the
-            // system process.
-            Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e);
-            return null;
-        } finally {
-            if (parser != null) parser.close();
-        }
-        return p;
+    @Override
+    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)
+            throws RemoteException {
+        getImplForUser().notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
     }
 
-    int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
-        PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
-        if (pkgInfo == null || pkgInfo.applicationInfo == null) {
-            throw new PackageManager.NameNotFoundException();
-        }
-        return pkgInfo.applicationInfo.uid;
+    @Override
+    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views)
+            throws RemoteException {
+        getImplForUser().partiallyUpdateAppWidgetIds(appWidgetIds, views);
     }
 
-    int enforceCallingUid(String packageName) throws IllegalArgumentException {
-        int callingUid = getCallingUid();
-        int packageUid;
-        try {
-            packageUid = getUidForPackage(packageName);
-        } catch (PackageManager.NameNotFoundException ex) {
-            throw new IllegalArgumentException("packageName and uid don't match packageName="
-                    + packageName);
-        }
-        if (callingUid != packageUid) {
-            throw new IllegalArgumentException("packageName and uid don't match packageName="
-                    + packageName);
-        }
-        return callingUid;
+    @Override
+    public void stopListening(int hostId) throws RemoteException {
+        getImplForUser().stopListening(hostId);
     }
 
-    void sendInitialBroadcasts() {
-        synchronized (mAppWidgetIds) {
-            ensureStateLoadedLocked();
-            final int N = mInstalledProviders.size();
-            for (int i=0; i<N; i++) {
-                Provider p = mInstalledProviders.get(i);
-                if (p.instances.size() > 0) {
-                    sendEnableIntentLocked(p);
-                    int[] appWidgetIds = getAppWidgetIds(p);
-                    sendUpdateIntentLocked(p, appWidgetIds);
-                    registerForBroadcastsLocked(p, appWidgetIds);
-                }
-            }
-        }
+    @Override
+    public void unbindRemoteViewsService(int appWidgetId, Intent intent) throws RemoteException {
+        getImplForUser().unbindRemoteViewsService(appWidgetId, intent);
     }
 
-    // only call from initialization -- it assumes that the data structures are all empty
-    void loadStateLocked() {
-        AtomicFile file = savedStateFile();
-        try {
-            FileInputStream stream = file.openRead();
-            readStateFromFileLocked(stream);
-
-            if (stream != null) {
-                try {
-                    stream.close();
-                } catch (IOException e) {
-                    Slog.w(TAG, "Failed to close state FileInputStream " + e);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            Slog.w(TAG, "Failed to read state: " + e);
-        }
+    @Override
+    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) throws RemoteException {
+        getImplForUser().updateAppWidgetIds(appWidgetIds, views);
     }
 
-    void saveStateLocked() {
-        AtomicFile file = savedStateFile();
-        FileOutputStream stream;
-        try {
-            stream = file.startWrite();
-            if (writeStateToFileLocked(stream)) {
-                file.finishWrite(stream);
-            } else {
-                file.failWrite(stream);
-                Slog.w(TAG, "Failed to save state, restoring backup.");
-            }
-        } catch (IOException e) {
-            Slog.w(TAG, "Failed open state file for write: " + e);
-        }
+    @Override
+    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views)
+            throws RemoteException {
+        getImplForUser().updateAppWidgetProvider(provider, views);
     }
 
-    boolean writeStateToFileLocked(FileOutputStream stream) {
-        int N;
-
-        try {
-            XmlSerializer out = new FastXmlSerializer();
-            out.setOutput(stream, "utf-8");
-            out.startDocument(null, true);
-            out.startTag(null, "gs");
-
-            int providerIndex = 0;
-            N = mInstalledProviders.size();
-            for (int i=0; i<N; i++) {
-                Provider p = mInstalledProviders.get(i);
-                if (p.instances.size() > 0) {
-                    out.startTag(null, "p");
-                    out.attribute(null, "pkg", p.info.provider.getPackageName());
-                    out.attribute(null, "cl", p.info.provider.getClassName());
-                    out.endTag(null, "p");
-                    p.tag = providerIndex;
-                    providerIndex++;
-                }
-            }
-
-            N = mHosts.size();
-            for (int i=0; i<N; i++) {
-                Host host = mHosts.get(i);
-                out.startTag(null, "h");
-                out.attribute(null, "pkg", host.packageName);
-                out.attribute(null, "id", Integer.toHexString(host.hostId));
-                out.endTag(null, "h");
-                host.tag = i;
-            }
-
-            N = mAppWidgetIds.size();
-            for (int i=0; i<N; i++) {
-                AppWidgetId id = mAppWidgetIds.get(i);
-                out.startTag(null, "g");
-                out.attribute(null, "id", Integer.toHexString(id.appWidgetId));
-                out.attribute(null, "h", Integer.toHexString(id.host.tag));
-                if (id.provider != null) {
-                    out.attribute(null, "p", Integer.toHexString(id.provider.tag));
-                }
-                out.endTag(null, "g");
-            }
-
-            out.endTag(null, "gs");
-
-            out.endDocument();
-            return true;
-        } catch (IOException e) {
-            Slog.w(TAG, "Failed to write state: " + e);
-            return false;
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        // Dump the state of all the app widget providers
+        for (int i = 0; i < mAppWidgetServices.size(); i++) {
+            AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+            service.dump(fd, pw, args);
         }
     }
 
-    void readStateFromFileLocked(FileInputStream stream) {
-        boolean success = false;
-
-        try {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(stream, null);
-
-            int type;
-            int providerIndex = 0;
-            HashMap<Integer,Provider> loadedProviders = new HashMap<Integer, Provider>();
-            do {
-                type = parser.next();
-                if (type == XmlPullParser.START_TAG) {
-                    String tag = parser.getName();
-                    if ("p".equals(tag)) {
-                        // TODO: do we need to check that this package has the same signature
-                        // as before?
-                        String pkg = parser.getAttributeValue(null, "pkg");
-                        String cl = parser.getAttributeValue(null, "cl");
-
-                        final PackageManager packageManager = mContext.getPackageManager();
-                        try {
-                            packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0);
-                        } catch (PackageManager.NameNotFoundException e) {
-                            String[] pkgs = packageManager.currentToCanonicalPackageNames(
-                                    new String[] { pkg });
-                            pkg = pkgs[0];
-                        }
-
-                        Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
-                        if (p == null && mSafeMode) {
-                            // if we're in safe mode, make a temporary one
-                            p = new Provider();
-                            p.info = new AppWidgetProviderInfo();
-                            p.info.provider = new ComponentName(pkg, cl);
-                            p.zombie = true;
-                            mInstalledProviders.add(p);
-                        }
-                        if (p != null) {
-                            // if it wasn't uninstalled or something
-                            loadedProviders.put(providerIndex, p);
-                        }
-                        providerIndex++;
-                    }
-                    else if ("h".equals(tag)) {
-                        Host host = new Host();
-
-                        // TODO: do we need to check that this package has the same signature
-                        // as before?
-                        host.packageName = parser.getAttributeValue(null, "pkg");
-                        try {
-                            host.uid = getUidForPackage(host.packageName);
-                        } catch (PackageManager.NameNotFoundException ex) {
-                            host.zombie = true;
-                        }
-                        if (!host.zombie || mSafeMode) {
-                            // In safe mode, we don't discard the hosts we don't recognize
-                            // so that they're not pruned from our list.  Otherwise, we do.
-                            host.hostId = Integer.parseInt(
-                                    parser.getAttributeValue(null, "id"), 16);
-                            mHosts.add(host);
-                        }
-                    }
-                    else if ("g".equals(tag)) {
-                        AppWidgetId id = new AppWidgetId();
-                        id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16);
-                        if (id.appWidgetId >= mNextAppWidgetId) {
-                            mNextAppWidgetId = id.appWidgetId + 1;
-                        }
-
-                        String providerString = parser.getAttributeValue(null, "p");
-                        if (providerString != null) {
-                            // there's no provider if it hasn't been bound yet.
-                            // maybe we don't have to save this, but it brings the system
-                            // to the state it was in.
-                            int pIndex = Integer.parseInt(providerString, 16);
-                            id.provider = loadedProviders.get(pIndex);
-                            if (false) {
-                                Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
-                                        + pIndex + " which is " + id.provider);
-                            }
-                            if (id.provider == null) {
-                                // This provider is gone.  We just let the host figure out
-                                // that this happened when it fails to load it.
-                                continue;
-                            }
-                        }
-
-                        int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16);
-                        id.host = mHosts.get(hIndex);
-                        if (id.host == null) {
-                            // This host is gone.
-                            continue;
-                        }
-
-                        if (id.provider != null) {
-                            id.provider.instances.add(id);
-                        }
-                        id.host.instances.add(id);
-                        mAppWidgetIds.add(id);
-                    }
-                }
-            } while (type != XmlPullParser.END_DOCUMENT);
-            success = true;
-        } catch (NullPointerException e) {
-            Slog.w(TAG, "failed parsing " + e);
-        } catch (NumberFormatException e) {
-            Slog.w(TAG, "failed parsing " + e);
-        } catch (XmlPullParserException e) {
-            Slog.w(TAG, "failed parsing " + e);
-        } catch (IOException e) {
-            Slog.w(TAG, "failed parsing " + e);
-        } catch (IndexOutOfBoundsException e) {
-            Slog.w(TAG, "failed parsing " + e);
-        }
-
-        if (success) {
-            // delete any hosts that didn't manage to get connected (should happen)
-            // if it matters, they'll be reconnected.
-            for (int i=mHosts.size()-1; i>=0; i--) {
-                pruneHostLocked(mHosts.get(i));
-            }
-        } else {
-            // failed reading, clean up
-            Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
-
-            mAppWidgetIds.clear();
-            mHosts.clear();
-            final int N = mInstalledProviders.size();
-            for (int i=0; i<N; i++) {
-                mInstalledProviders.get(i).instances.clear();
-            }
-        }
-    }
-
-    AtomicFile savedStateFile() {
-        return new AtomicFile(new File("/data/system/" + SETTINGS_FILENAME));
-    }
-
     BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            //Slog.d(TAG, "received " + action);
+            // Slog.d(TAG, "received " + action);
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
-                sendInitialBroadcasts();
+                getImplForUser().sendInitialBroadcasts();
             } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                Locale revised = Locale.getDefault();
-                if (revised == null || mLocale == null ||
-                    !(revised.equals(mLocale))) {
-                    mLocale = revised;
-
-                    synchronized (mAppWidgetIds) {
-                        ensureStateLoadedLocked();
-                        int N = mInstalledProviders.size();
-                        for (int i=N-1; i>=0; i--) {
-                            Provider p = mInstalledProviders.get(i);
-                            String pkgName = p.info.provider.getPackageName();
-                            updateProvidersForPackageLocked(pkgName);
-                        }
-                        saveStateLocked();
-                    }
+                for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                    service.onConfigurationChanged();
                 }
             } else {
-                boolean added = false;
-                boolean changed = false;
-                String pkgList[] = null;
-                if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
-                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                    added = true;
-                } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
-                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                    added = false;
-                } else  {
-                    Uri uri = intent.getData();
-                    if (uri == null) {
-                        return;
-                    }
-                    String pkgName = uri.getSchemeSpecificPart();
-                    if (pkgName == null) {
-                        return;
-                    }
-                    pkgList = new String[] { pkgName };
-                    added = Intent.ACTION_PACKAGE_ADDED.equals(action);
-                    changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
-                }
-                if (pkgList == null || pkgList.length == 0) {
-                    return;
-                }
-                if (added || changed) {
-                    synchronized (mAppWidgetIds) {
-                        ensureStateLoadedLocked();
-                        Bundle extras = intent.getExtras();
-                        if (changed || (extras != null &&
-                                    extras.getBoolean(Intent.EXTRA_REPLACING, false))) {
-                            for (String pkgName : pkgList) {
-                                // The package was just upgraded
-                                updateProvidersForPackageLocked(pkgName);
-                            }
-                        } else {
-                            // The package was just added
-                            for (String pkgName : pkgList) {
-                                addProvidersForPackageLocked(pkgName);
-                            }
-                        }
-                        saveStateLocked();
-                    }
-                } else {
-                    Bundle extras = intent.getExtras();
-                    if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
-                        // The package is being updated.  We'll receive a PACKAGE_ADDED shortly.
-                    } else {
-                        synchronized (mAppWidgetIds) {
-                            ensureStateLoadedLocked();
-                            for (String pkgName : pkgList) {
-                                removeProvidersForPackageLocked(pkgName);
-                                saveStateLocked();
-                            }
-                        }
-                    }
-                }
+                // TODO: Verify that this only needs to be delivered for the related user and not
+                // all the users
+                getImplForUser().onBroadcastReceived(intent);
             }
         }
     };
-
-    void addProvidersForPackageLocked(String pkgName) {
-        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
-        intent.setPackage(pkgName);
-        List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
-                PackageManager.GET_META_DATA);
-
-        final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
-        for (int i=0; i<N; i++) {
-            ResolveInfo ri = broadcastReceivers.get(i);
-            ActivityInfo ai = ri.activityInfo;
-            if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
-                continue;
-            }
-            if (pkgName.equals(ai.packageName)) {
-                addProviderLocked(ri);
-            }
-        }
-    }
-
-    void updateProvidersForPackageLocked(String pkgName) {
-        HashSet<String> keep = new HashSet<String>();
-        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
-        intent.setPackage(pkgName);
-        List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
-                PackageManager.GET_META_DATA);
-
-        // add the missing ones and collect which ones to keep
-        int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
-        for (int i=0; i<N; i++) {
-            ResolveInfo ri = broadcastReceivers.get(i);
-            ActivityInfo ai = ri.activityInfo;
-            if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
-                continue;
-            }
-            if (pkgName.equals(ai.packageName)) {
-                ComponentName component = new ComponentName(ai.packageName, ai.name);
-                Provider p = lookupProviderLocked(component);
-                if (p == null) {
-                    if (addProviderLocked(ri)) {
-                        keep.add(ai.name);
-                    }
-                } else {
-                    Provider parsed = parseProviderInfoXml(component, ri);
-                    if (parsed != null) {
-                        keep.add(ai.name);
-                        // Use the new AppWidgetProviderInfo.
-                        p.info = parsed.info;
-                        // If it's enabled
-                        final int M = p.instances.size();
-                        if (M > 0) {
-                            int[] appWidgetIds = getAppWidgetIds(p);
-                            // Reschedule for the new updatePeriodMillis (don't worry about handling
-                            // it specially if updatePeriodMillis didn't change because we just sent
-                            // an update, and the next one will be updatePeriodMillis from now).
-                            cancelBroadcasts(p);
-                            registerForBroadcastsLocked(p, appWidgetIds);
-                            // If it's currently showing, call back with the new AppWidgetProviderInfo.
-                            for (int j=0; j<M; j++) {
-                                AppWidgetId id = p.instances.get(j);
-                                id.views = null;
-                                if (id.host != null && id.host.callbacks != null) {
-                                    try {
-                                        id.host.callbacks.providerChanged(id.appWidgetId, p.info);
-                                    } catch (RemoteException ex) {
-                                        // It failed; remove the callback. No need to prune because
-                                        // we know that this host is still referenced by this
-                                        // instance.
-                                        id.host.callbacks = null;
-                                    }
-                                }
-                            }
-                            // Now that we've told the host, push out an update.
-                            sendUpdateIntentLocked(p, appWidgetIds);
-                        }
-                    }
-                }
-            }
-        }
-
-        // prune the ones we don't want to keep
-        N = mInstalledProviders.size();
-        for (int i=N-1; i>=0; i--) {
-            Provider p = mInstalledProviders.get(i);
-            if (pkgName.equals(p.info.provider.getPackageName())
-                    && !keep.contains(p.info.provider.getClassName())) {
-                removeProviderLocked(i, p);
-            }
-        }
-    }
-
-    void removeProvidersForPackageLocked(String pkgName) {
-        int N = mInstalledProviders.size();
-        for (int i=N-1; i>=0; i--) {
-            Provider p = mInstalledProviders.get(i);
-            if (pkgName.equals(p.info.provider.getPackageName())) {
-                removeProviderLocked(i, p);
-            }
-        }
-
-        // Delete the hosts for this package too
-        //
-        // By now, we have removed any AppWidgets that were in any hosts here,
-        // so we don't need to worry about sending DISABLE broadcasts to them.
-        N = mHosts.size();
-        for (int i=N-1; i>=0; i--) {
-            Host host = mHosts.get(i);
-            if (pkgName.equals(host.packageName)) {
-                deleteHostLocked(host);
-            }
-        }
-    }
 }
-
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
new file mode 100644
index 0000000..41ede2e
--- /dev/null
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -0,0 +1,1608 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.Intent.FilterComparison;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserId;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.util.Xml;
+import android.widget.RemoteViews;
+
+import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.widget.IRemoteViewsAdapterConnection;
+import com.android.internal.widget.IRemoteViewsFactory;
+import com.android.server.am.ActivityManagerService;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+class AppWidgetServiceImpl {
+
+    private static final String TAG = "AppWidgetServiceImpl";
+    private static final String SETTINGS_FILENAME = "appwidgets.xml";
+    private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
+
+    /*
+     * When identifying a Host or Provider based on the calling process, use the uid field. When
+     * identifying a Host or Provider based on a package manager broadcast, use the package given.
+     */
+
+    static class Provider {
+        int uid;
+        AppWidgetProviderInfo info;
+        ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
+        PendingIntent broadcast;
+        boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
+
+        int tag; // for use while saving state (the index)
+    }
+
+    static class Host {
+        int uid;
+        int hostId;
+        String packageName;
+        ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
+        IAppWidgetHost callbacks;
+        boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
+
+        int tag; // for use while saving state (the index)
+    }
+
+    static class AppWidgetId {
+        int appWidgetId;
+        Provider provider;
+        RemoteViews views;
+        Host host;
+    }
+
+    /**
+     * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. This
+     * needs to be a static inner class since a reference to the ServiceConnection is held globally
+     * and may lead us to leak AppWidgetService instances (if there were more than one).
+     */
+    static class ServiceConnectionProxy implements ServiceConnection {
+        private final IBinder mConnectionCb;
+
+        ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
+            mConnectionCb = connectionCb;
+        }
+
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            final IRemoteViewsAdapterConnection cb = IRemoteViewsAdapterConnection.Stub
+                    .asInterface(mConnectionCb);
+            try {
+                cb.onServiceConnected(service);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+            disconnect();
+        }
+
+        public void disconnect() {
+            final IRemoteViewsAdapterConnection cb = IRemoteViewsAdapterConnection.Stub
+                    .asInterface(mConnectionCb);
+            try {
+                cb.onServiceDisconnected();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    // Manages active connections to RemoteViewsServices
+    private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection> mBoundRemoteViewsServices = new HashMap<Pair<Integer, FilterComparison>, ServiceConnection>();
+    // Manages persistent references to RemoteViewsServices from different App Widgets
+    private final HashMap<FilterComparison, HashSet<Integer>> mRemoteViewsServicesAppWidgets = new HashMap<FilterComparison, HashSet<Integer>>();
+
+    Context mContext;
+    Locale mLocale;
+    PackageManager mPackageManager;
+    AlarmManager mAlarmManager;
+    ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
+    int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
+    final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
+    ArrayList<Host> mHosts = new ArrayList<Host>();
+    boolean mSafeMode;
+    int mUserId;
+    boolean mStateLoaded;
+
+    // These are for debugging only -- widgets are going missing in some rare instances
+    ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>();
+    ArrayList<Host> mDeletedHosts = new ArrayList<Host>();
+
+    AppWidgetServiceImpl(Context context, int userId) {
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        mUserId = userId;
+    }
+
+    public void systemReady(boolean safeMode) {
+        mSafeMode = safeMode;
+
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+        }
+    }
+
+    void onConfigurationChanged() {
+        Locale revised = Locale.getDefault();
+        if (revised == null || mLocale == null || !(revised.equals(mLocale))) {
+            mLocale = revised;
+
+            synchronized (mAppWidgetIds) {
+                ensureStateLoadedLocked();
+                int N = mInstalledProviders.size();
+                for (int i = N - 1; i >= 0; i--) {
+                    Provider p = mInstalledProviders.get(i);
+                    String pkgName = p.info.provider.getPackageName();
+                    updateProvidersForPackageLocked(pkgName);
+                }
+                saveStateLocked();
+            }
+        }
+    }
+
+    void onBroadcastReceived(Intent intent) {
+        final String action = intent.getAction();
+        boolean added = false;
+        boolean changed = false;
+        String pkgList[] = null;
+        if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+            pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+            added = true;
+        } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+            pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+            added = false;
+        } else {
+            Uri uri = intent.getData();
+            if (uri == null) {
+                return;
+            }
+            String pkgName = uri.getSchemeSpecificPart();
+            if (pkgName == null) {
+                return;
+            }
+            pkgList = new String[] { pkgName };
+            added = Intent.ACTION_PACKAGE_ADDED.equals(action);
+            changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
+        }
+        if (pkgList == null || pkgList.length == 0) {
+            return;
+        }
+        if (added || changed) {
+            synchronized (mAppWidgetIds) {
+                ensureStateLoadedLocked();
+                Bundle extras = intent.getExtras();
+                if (changed
+                        || (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false))) {
+                    for (String pkgName : pkgList) {
+                        // The package was just upgraded
+                        updateProvidersForPackageLocked(pkgName);
+                    }
+                } else {
+                    // The package was just added
+                    for (String pkgName : pkgList) {
+                        addProvidersForPackageLocked(pkgName);
+                    }
+                }
+                saveStateLocked();
+            }
+        } else {
+            Bundle extras = intent.getExtras();
+            if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+                // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
+            } else {
+                synchronized (mAppWidgetIds) {
+                    ensureStateLoadedLocked();
+                    for (String pkgName : pkgList) {
+                        removeProvidersForPackageLocked(pkgName);
+                        saveStateLocked();
+                    }
+                }
+            }
+        }
+    }
+
+    private void dumpProvider(Provider p, int index, PrintWriter pw) {
+        AppWidgetProviderInfo info = p.info;
+        pw.print("  ["); pw.print(index); pw.print("] provider ");
+                pw.print(info.provider.flattenToShortString());
+                pw.println(':');
+        pw.print("    min=("); pw.print(info.minWidth);
+                pw.print("x"); pw.print(info.minHeight);
+        pw.print(")   minResize=("); pw.print(info.minResizeWidth);
+                pw.print("x"); pw.print(info.minResizeHeight);
+                pw.print(") updatePeriodMillis=");
+                pw.print(info.updatePeriodMillis);
+                pw.print(" resizeMode=");
+                pw.print(info.resizeMode);
+                pw.print(" autoAdvanceViewId=");
+                pw.print(info.autoAdvanceViewId);
+                pw.print(" initialLayout=#");
+                pw.print(Integer.toHexString(info.initialLayout));
+                pw.print(" zombie="); pw.println(p.zombie);
+    }
+
+    private void dumpHost(Host host, int index, PrintWriter pw) {
+        pw.print("  ["); pw.print(index); pw.print("] hostId=");
+                pw.print(host.hostId); pw.print(' ');
+                pw.print(host.packageName); pw.print('/');
+        pw.print(host.uid); pw.println(':');
+        pw.print("    callbacks="); pw.println(host.callbacks);
+        pw.print("    instances.size="); pw.print(host.instances.size());
+                pw.print(" zombie="); pw.println(host.zombie);
+    }
+
+    private void dumpAppWidgetId(AppWidgetId id, int index, PrintWriter pw) {
+        pw.print("  ["); pw.print(index); pw.print("] id=");
+                pw.println(id.appWidgetId);
+        pw.print("    hostId=");
+                pw.print(id.host.hostId); pw.print(' ');
+                pw.print(id.host.packageName); pw.print('/');
+                pw.println(id.host.uid);
+        if (id.provider != null) {
+            pw.print("    provider=");
+                    pw.println(id.provider.info.provider.flattenToShortString());
+        }
+        if (id.host != null) {
+            pw.print("    host.callbacks="); pw.println(id.host.callbacks);
+        }
+        if (id.views != null) {
+            pw.print("    views="); pw.println(id.views);
+        }
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        synchronized (mAppWidgetIds) {
+            int N = mInstalledProviders.size();
+            pw.println("Providers:");
+            for (int i=0; i<N; i++) {
+                dumpProvider(mInstalledProviders.get(i), i, pw);
+            }
+
+            N = mAppWidgetIds.size();
+            pw.println(" ");
+            pw.println("AppWidgetIds:");
+            for (int i=0; i<N; i++) {
+                dumpAppWidgetId(mAppWidgetIds.get(i), i, pw);
+            }
+
+            N = mHosts.size();
+            pw.println(" ");
+            pw.println("Hosts:");
+            for (int i=0; i<N; i++) {
+                dumpHost(mHosts.get(i), i, pw);
+            }
+
+            N = mDeletedProviders.size();
+            pw.println(" ");
+            pw.println("Deleted Providers:");
+            for (int i=0; i<N; i++) {
+                dumpProvider(mDeletedProviders.get(i), i, pw);
+            }
+
+            N = mDeletedHosts.size();
+            pw.println(" ");
+            pw.println("Deleted Hosts:");
+            for (int i=0; i<N; i++) {
+                dumpHost(mDeletedHosts.get(i), i, pw);
+            }
+        }
+    }
+
+    private void ensureStateLoadedLocked() {
+        if (!mStateLoaded) {
+            loadAppWidgetList();
+            loadStateLocked();
+            mStateLoaded = true;
+        }
+    }
+
+    public int allocateAppWidgetId(String packageName, int hostId) {
+        int callingUid = enforceCallingUid(packageName);
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            int appWidgetId = mNextAppWidgetId++;
+
+            Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
+
+            AppWidgetId id = new AppWidgetId();
+            id.appWidgetId = appWidgetId;
+            id.host = host;
+
+            host.instances.add(id);
+            mAppWidgetIds.add(id);
+
+            saveStateLocked();
+
+            return appWidgetId;
+        }
+    }
+
+    public void deleteAppWidgetId(int appWidgetId) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+            if (id != null) {
+                deleteAppWidgetLocked(id);
+                saveStateLocked();
+            }
+        }
+    }
+
+    public void deleteHost(int hostId) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            int callingUid = Binder.getCallingUid();
+            Host host = lookupHostLocked(callingUid, hostId);
+            if (host != null) {
+                deleteHostLocked(host);
+                saveStateLocked();
+            }
+        }
+    }
+
+    public void deleteAllHosts() {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            int callingUid = Binder.getCallingUid();
+            final int N = mHosts.size();
+            boolean changed = false;
+            for (int i = N - 1; i >= 0; i--) {
+                Host host = mHosts.get(i);
+                if (host.uid == callingUid) {
+                    deleteHostLocked(host);
+                    changed = true;
+                }
+            }
+            if (changed) {
+                saveStateLocked();
+            }
+        }
+    }
+
+    void deleteHostLocked(Host host) {
+        final int N = host.instances.size();
+        for (int i = N - 1; i >= 0; i--) {
+            AppWidgetId id = host.instances.get(i);
+            deleteAppWidgetLocked(id);
+        }
+        host.instances.clear();
+        mHosts.remove(host);
+        mDeletedHosts.add(host);
+        // it's gone or going away, abruptly drop the callback connection
+        host.callbacks = null;
+    }
+
+    void deleteAppWidgetLocked(AppWidgetId id) {
+        // We first unbind all services that are bound to this id
+        unbindAppWidgetRemoteViewsServicesLocked(id);
+
+        Host host = id.host;
+        host.instances.remove(id);
+        pruneHostLocked(host);
+
+        mAppWidgetIds.remove(id);
+
+        Provider p = id.provider;
+        if (p != null) {
+            p.instances.remove(id);
+            if (!p.zombie) {
+                // send the broacast saying that this appWidgetId has been deleted
+                Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
+                intent.setComponent(p.info.provider);
+                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
+                mContext.sendBroadcast(intent);
+                if (p.instances.size() == 0) {
+                    // cancel the future updates
+                    cancelBroadcasts(p);
+
+                    // send the broacast saying that the provider is not in use any more
+                    intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
+                    intent.setComponent(p.info.provider);
+                    mContext.sendBroadcast(intent);
+                }
+            }
+        }
+    }
+
+    void cancelBroadcasts(Provider p) {
+        if (p.broadcast != null) {
+            mAlarmManager.cancel(p.broadcast);
+            long token = Binder.clearCallingIdentity();
+            try {
+                p.broadcast.cancel();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            p.broadcast = null;
+        }
+    }
+
+    public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
+        mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
+                "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mAppWidgetIds) {
+                ensureStateLoadedLocked();
+                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+                if (id == null) {
+                    throw new IllegalArgumentException("bad appWidgetId");
+                }
+                if (id.provider != null) {
+                    throw new IllegalArgumentException("appWidgetId " + appWidgetId
+                            + " already bound to " + id.provider.info.provider);
+                }
+                Provider p = lookupProviderLocked(provider);
+                if (p == null) {
+                    throw new IllegalArgumentException("not a appwidget provider: " + provider);
+                }
+                if (p.zombie) {
+                    throw new IllegalArgumentException("can't bind to a 3rd party provider in"
+                            + " safe mode: " + provider);
+                }
+
+                Binder.restoreCallingIdentity(ident);
+
+                id.provider = p;
+                p.instances.add(id);
+                int instancesSize = p.instances.size();
+                if (instancesSize == 1) {
+                    // tell the provider that it's ready
+                    sendEnableIntentLocked(p);
+                }
+
+                // send an update now -- We need this update now, and just for this appWidgetId.
+                // It's less critical when the next one happens, so when we schedule the next one,
+                // we add updatePeriodMillis to its start time. That time will have some slop,
+                // but that's okay.
+                sendUpdateIntentLocked(p, new int[] { appWidgetId });
+
+                // schedule the future updates
+                registerForBroadcastsLocked(p, getAppWidgetIds(p));
+                saveStateLocked();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    // Binds to a specific RemoteViewsService
+    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+            if (id == null) {
+                throw new IllegalArgumentException("bad appWidgetId");
+            }
+            final ComponentName componentName = intent.getComponent();
+            try {
+                final ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName,
+                        PackageManager.GET_PERMISSIONS);
+                if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(si.permission)) {
+                    throw new SecurityException("Selected service does not require "
+                            + android.Manifest.permission.BIND_REMOTEVIEWS + ": " + componentName);
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                throw new IllegalArgumentException("Unknown component " + componentName);
+            }
+
+            // If there is already a connection made for this service intent, then disconnect from
+            // that first. (This does not allow multiple connections to the same service under
+            // the same key)
+            ServiceConnectionProxy conn = null;
+            FilterComparison fc = new FilterComparison(intent);
+            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc);
+            if (mBoundRemoteViewsServices.containsKey(key)) {
+                conn = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key);
+                conn.disconnect();
+                mContext.unbindService(conn);
+                mBoundRemoteViewsServices.remove(key);
+            }
+
+            int userId = UserId.getUserId(id.provider.uid);
+            // Bind to the RemoteViewsService (which will trigger a callback to the
+            // RemoteViewsAdapter.onServiceConnected())
+            final long token = Binder.clearCallingIdentity();
+            try {
+                conn = new ServiceConnectionProxy(key, connection);
+                mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
+                mBoundRemoteViewsServices.put(key, conn);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+
+            // Add it to the mapping of RemoteViewsService to appWidgetIds so that we can determine
+            // when we can call back to the RemoteViewsService later to destroy associated
+            // factories.
+            incrementAppWidgetServiceRefCount(appWidgetId, fc);
+        }
+    }
+
+    // Unbinds from a specific RemoteViewsService
+    public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            // Unbind from the RemoteViewsService (which will trigger a callback to the bound
+            // RemoteViewsAdapter)
+            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, new FilterComparison(
+                    intent));
+            if (mBoundRemoteViewsServices.containsKey(key)) {
+                // We don't need to use the appWidgetId until after we are sure there is something
+                // to unbind. Note that this may mask certain issues with apps calling unbind()
+                // more than necessary.
+                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+                if (id == null) {
+                    throw new IllegalArgumentException("bad appWidgetId");
+                }
+
+                ServiceConnectionProxy conn = (ServiceConnectionProxy) mBoundRemoteViewsServices
+                        .get(key);
+                conn.disconnect();
+                mContext.unbindService(conn);
+                mBoundRemoteViewsServices.remove(key);
+            } else {
+                Log.e("AppWidgetService", "Error (unbindRemoteViewsService): Connection not bound");
+            }
+        }
+    }
+
+    // Unbinds from a RemoteViewsService when we delete an app widget
+    private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) {
+        int appWidgetId = id.appWidgetId;
+        // Unbind all connections to Services bound to this AppWidgetId
+        Iterator<Pair<Integer, Intent.FilterComparison>> it = mBoundRemoteViewsServices.keySet()
+                .iterator();
+        while (it.hasNext()) {
+            final Pair<Integer, Intent.FilterComparison> key = it.next();
+            if (key.first.intValue() == appWidgetId) {
+                final ServiceConnectionProxy conn = (ServiceConnectionProxy) mBoundRemoteViewsServices
+                        .get(key);
+                conn.disconnect();
+                mContext.unbindService(conn);
+                it.remove();
+            }
+        }
+
+        // Check if we need to destroy any services (if no other app widgets are
+        // referencing the same service)
+        decrementAppWidgetServiceRefCount(id);
+    }
+
+    // Destroys the cached factory on the RemoteViewsService's side related to the specified intent
+    private void destroyRemoteViewsService(final Intent intent, AppWidgetId id) {
+        final ServiceConnection conn = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                final IRemoteViewsFactory cb = IRemoteViewsFactory.Stub.asInterface(service);
+                try {
+                    cb.onDestroy(intent);
+                } catch (RemoteException e) {
+                    e.printStackTrace();
+                } catch (RuntimeException e) {
+                    e.printStackTrace();
+                }
+                mContext.unbindService(this);
+            }
+
+            @Override
+            public void onServiceDisconnected(android.content.ComponentName name) {
+                // Do nothing
+            }
+        };
+
+        int userId = UserId.getUserId(id.provider.uid);
+        // Bind to the service and remove the static intent->factory mapping in the
+        // RemoteViewsService.
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Adds to the ref-count for a given RemoteViewsService intent
+    private void incrementAppWidgetServiceRefCount(int appWidgetId, FilterComparison fc) {
+        HashSet<Integer> appWidgetIds = null;
+        if (mRemoteViewsServicesAppWidgets.containsKey(fc)) {
+            appWidgetIds = mRemoteViewsServicesAppWidgets.get(fc);
+        } else {
+            appWidgetIds = new HashSet<Integer>();
+            mRemoteViewsServicesAppWidgets.put(fc, appWidgetIds);
+        }
+        appWidgetIds.add(appWidgetId);
+    }
+
+    // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
+    // the ref-count reaches zero.
+    private void decrementAppWidgetServiceRefCount(AppWidgetId id) {
+        Iterator<FilterComparison> it = mRemoteViewsServicesAppWidgets.keySet().iterator();
+        while (it.hasNext()) {
+            final FilterComparison key = it.next();
+            final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
+            if (ids.remove(id.appWidgetId)) {
+                // If we have removed the last app widget referencing this service, then we
+                // should destroy it and remove it from this set
+                if (ids.isEmpty()) {
+                    destroyRemoteViewsService(key.getIntent(), id);
+                    it.remove();
+                }
+            }
+        }
+    }
+
+    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+            if (id != null && id.provider != null && !id.provider.zombie) {
+                return id.provider.info;
+            }
+            return null;
+        }
+    }
+
+    public RemoteViews getAppWidgetViews(int appWidgetId) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
+            if (id != null) {
+                return id.views;
+            }
+            return null;
+        }
+    }
+
+    public List<AppWidgetProviderInfo> getInstalledProviders() {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            final int N = mInstalledProviders.size();
+            ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N);
+            for (int i = 0; i < N; i++) {
+                Provider p = mInstalledProviders.get(i);
+                if (!p.zombie) {
+                    result.add(p.info);
+                }
+            }
+            return result;
+        }
+    }
+
+    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
+        if (appWidgetIds == null) {
+            return;
+        }
+        if (appWidgetIds.length == 0) {
+            return;
+        }
+        final int N = appWidgetIds.length;
+
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            for (int i = 0; i < N; i++) {
+                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
+                updateAppWidgetInstanceLocked(id, views);
+            }
+        }
+    }
+
+    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) {
+        if (appWidgetIds == null) {
+            return;
+        }
+        if (appWidgetIds.length == 0) {
+            return;
+        }
+        final int N = appWidgetIds.length;
+
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            for (int i = 0; i < N; i++) {
+                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
+                updateAppWidgetInstanceLocked(id, views, true);
+            }
+        }
+    }
+
+    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
+        if (appWidgetIds == null) {
+            return;
+        }
+        if (appWidgetIds.length == 0) {
+            return;
+        }
+        final int N = appWidgetIds.length;
+
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            for (int i = 0; i < N; i++) {
+                AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]);
+                notifyAppWidgetViewDataChangedInstanceLocked(id, viewId);
+            }
+        }
+    }
+
+    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            Provider p = lookupProviderLocked(provider);
+            if (p == null) {
+                Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider);
+                return;
+            }
+            ArrayList<AppWidgetId> instances = p.instances;
+            final int callingUid = Binder.getCallingUid();
+            final int N = instances.size();
+            for (int i = 0; i < N; i++) {
+                AppWidgetId id = instances.get(i);
+                if (canAccessAppWidgetId(id, callingUid)) {
+                    updateAppWidgetInstanceLocked(id, views);
+                }
+            }
+        }
+    }
+
+    void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) {
+        updateAppWidgetInstanceLocked(id, views, false);
+    }
+
+    void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate) {
+        // allow for stale appWidgetIds and other badness
+        // lookup also checks that the calling process can access the appWidgetId
+        // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
+        if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
+
+            // We do not want to save this RemoteViews
+            if (!isPartialUpdate)
+                id.views = views;
+
+            // is anyone listening?
+            if (id.host.callbacks != null) {
+                try {
+                    // the lock is held, but this is a oneway call
+                    id.host.callbacks.updateAppWidget(id.appWidgetId, views);
+                } catch (RemoteException e) {
+                    // It failed; remove the callback. No need to prune because
+                    // we know that this host is still referenced by this instance.
+                    id.host.callbacks = null;
+                }
+            }
+        }
+    }
+
+    void notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, int viewId) {
+        // allow for stale appWidgetIds and other badness
+        // lookup also checks that the calling process can access the appWidgetId
+        // drop unbound appWidgetIds (shouldn't be possible under normal circumstances)
+        if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) {
+            // is anyone listening?
+            if (id.host.callbacks != null) {
+                try {
+                    // the lock is held, but this is a oneway call
+                    id.host.callbacks.viewDataChanged(id.appWidgetId, viewId);
+                } catch (RemoteException e) {
+                    // It failed; remove the callback. No need to prune because
+                    // we know that this host is still referenced by this instance.
+                    id.host.callbacks = null;
+                }
+            }
+
+            // If the host is unavailable, then we call the associated
+            // RemoteViewsFactory.onDataSetChanged() directly
+            if (id.host.callbacks == null) {
+                Set<FilterComparison> keys = mRemoteViewsServicesAppWidgets.keySet();
+                for (FilterComparison key : keys) {
+                    if (mRemoteViewsServicesAppWidgets.get(key).contains(id.appWidgetId)) {
+                        Intent intent = key.getIntent();
+
+                        final ServiceConnection conn = new ServiceConnection() {
+                            @Override
+                            public void onServiceConnected(ComponentName name, IBinder service) {
+                                IRemoteViewsFactory cb = IRemoteViewsFactory.Stub
+                                        .asInterface(service);
+                                try {
+                                    cb.onDataSetChangedAsync();
+                                } catch (RemoteException e) {
+                                    e.printStackTrace();
+                                } catch (RuntimeException e) {
+                                    e.printStackTrace();
+                                }
+                                mContext.unbindService(this);
+                            }
+
+                            @Override
+                            public void onServiceDisconnected(android.content.ComponentName name) {
+                                // Do nothing
+                            }
+                        };
+
+                        int userId = UserId.getUserId(id.provider.uid);
+                        // Bind to the service and call onDataSetChanged()
+                        final long token = Binder.clearCallingIdentity();
+                        try {
+                            mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
+                        } finally {
+                            Binder.restoreCallingIdentity(token);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId,
+            List<RemoteViews> updatedViews) {
+        int callingUid = enforceCallingUid(packageName);
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            Host host = lookupOrAddHostLocked(callingUid, packageName, hostId);
+            host.callbacks = callbacks;
+
+            updatedViews.clear();
+
+            ArrayList<AppWidgetId> instances = host.instances;
+            int N = instances.size();
+            int[] updatedIds = new int[N];
+            for (int i = 0; i < N; i++) {
+                AppWidgetId id = instances.get(i);
+                updatedIds[i] = id.appWidgetId;
+                updatedViews.add(id.views);
+            }
+            return updatedIds;
+        }
+    }
+
+    public void stopListening(int hostId) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            Host host = lookupHostLocked(Binder.getCallingUid(), hostId);
+            if (host != null) {
+                host.callbacks = null;
+                pruneHostLocked(host);
+            }
+        }
+    }
+
+    boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) {
+        if (id.host.uid == callingUid) {
+            // Apps hosting the AppWidget have access to it.
+            return true;
+        }
+        if (id.provider != null && id.provider.uid == callingUid) {
+            // Apps providing the AppWidget have access to it (if the appWidgetId has been bound)
+            return true;
+        }
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET) == PackageManager.PERMISSION_GRANTED) {
+            // Apps that can bind have access to all appWidgetIds.
+            return true;
+        }
+        // Nobody else can access it.
+        return false;
+    }
+
+    AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) {
+        int callingUid = Binder.getCallingUid();
+        final int N = mAppWidgetIds.size();
+        for (int i = 0; i < N; i++) {
+            AppWidgetId id = mAppWidgetIds.get(i);
+            if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) {
+                return id;
+            }
+        }
+        return null;
+    }
+
+    Provider lookupProviderLocked(ComponentName provider) {
+        final int N = mInstalledProviders.size();
+        for (int i = 0; i < N; i++) {
+            Provider p = mInstalledProviders.get(i);
+            if (p.info.provider.equals(provider)) {
+                return p;
+            }
+        }
+        return null;
+    }
+
+    Host lookupHostLocked(int uid, int hostId) {
+        final int N = mHosts.size();
+        for (int i = 0; i < N; i++) {
+            Host h = mHosts.get(i);
+            if (h.uid == uid && h.hostId == hostId) {
+                return h;
+            }
+        }
+        return null;
+    }
+
+    Host lookupOrAddHostLocked(int uid, String packageName, int hostId) {
+        final int N = mHosts.size();
+        for (int i = 0; i < N; i++) {
+            Host h = mHosts.get(i);
+            if (h.hostId == hostId && h.packageName.equals(packageName)) {
+                return h;
+            }
+        }
+        Host host = new Host();
+        host.packageName = packageName;
+        host.uid = uid;
+        host.hostId = hostId;
+        mHosts.add(host);
+        return host;
+    }
+
+    void pruneHostLocked(Host host) {
+        if (host.instances.size() == 0 && host.callbacks == null) {
+            mHosts.remove(host);
+        }
+    }
+
+    void loadAppWidgetList() {
+        PackageManager pm = mPackageManager;
+
+        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+        List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
+                PackageManager.GET_META_DATA);
+
+        final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
+        for (int i = 0; i < N; i++) {
+            ResolveInfo ri = broadcastReceivers.get(i);
+            addProviderLocked(ri);
+        }
+    }
+
+    boolean addProviderLocked(ResolveInfo ri) {
+        if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+            return false;
+        }
+        if (!ri.activityInfo.isEnabled()) {
+            return false;
+        }
+        Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
+                ri.activityInfo.name), ri);
+        if (p != null) {
+            mInstalledProviders.add(p);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    void removeProviderLocked(int index, Provider p) {
+        int N = p.instances.size();
+        for (int i = 0; i < N; i++) {
+            AppWidgetId id = p.instances.get(i);
+            // Call back with empty RemoteViews
+            updateAppWidgetInstanceLocked(id, null);
+            // Stop telling the host about updates for this from now on
+            cancelBroadcasts(p);
+            // clear out references to this appWidgetId
+            id.host.instances.remove(id);
+            mAppWidgetIds.remove(id);
+            id.provider = null;
+            pruneHostLocked(id.host);
+            id.host = null;
+        }
+        p.instances.clear();
+        mInstalledProviders.remove(index);
+        mDeletedProviders.add(p);
+        // no need to send the DISABLE broadcast, since the receiver is gone anyway
+        cancelBroadcasts(p);
+    }
+
+    void sendEnableIntentLocked(Provider p) {
+        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
+        intent.setComponent(p.info.provider);
+        mContext.sendBroadcast(intent);
+    }
+
+    void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
+        if (appWidgetIds != null && appWidgetIds.length > 0) {
+            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
+            intent.setComponent(p.info.provider);
+            mContext.sendBroadcast(intent);
+        }
+    }
+
+    void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) {
+        if (p.info.updatePeriodMillis > 0) {
+            // if this is the first instance, set the alarm. otherwise,
+            // rely on the fact that we've already set it and that
+            // PendingIntent.getBroadcast will update the extras.
+            boolean alreadyRegistered = p.broadcast != null;
+            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
+            intent.setComponent(p.info.provider);
+            long token = Binder.clearCallingIdentity();
+            try {
+                p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
+                        PendingIntent.FLAG_UPDATE_CURRENT);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            if (!alreadyRegistered) {
+                long period = p.info.updatePeriodMillis;
+                if (period < MIN_UPDATE_PERIOD) {
+                    period = MIN_UPDATE_PERIOD;
+                }
+                mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock
+                        .elapsedRealtime()
+                        + period, period, p.broadcast);
+            }
+        }
+    }
+
+    static int[] getAppWidgetIds(Provider p) {
+        int instancesSize = p.instances.size();
+        int appWidgetIds[] = new int[instancesSize];
+        for (int i = 0; i < instancesSize; i++) {
+            appWidgetIds[i] = p.instances.get(i).appWidgetId;
+        }
+        return appWidgetIds;
+    }
+
+    public int[] getAppWidgetIds(ComponentName provider) {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            Provider p = lookupProviderLocked(provider);
+            if (p != null && Binder.getCallingUid() == p.uid) {
+                return getAppWidgetIds(p);
+            } else {
+                return new int[0];
+            }
+        }
+    }
+
+    private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
+        Provider p = null;
+
+        ActivityInfo activityInfo = ri.activityInfo;
+        XmlResourceParser parser = null;
+        try {
+            parser = activityInfo.loadXmlMetaData(mPackageManager,
+                    AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
+            if (parser == null) {
+                Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER
+                        + " meta-data for " + "AppWidget provider '" + component + '\'');
+                return null;
+            }
+
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            int type;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+                // drain whitespace, comments, etc.
+            }
+
+            String nodeName = parser.getName();
+            if (!"appwidget-provider".equals(nodeName)) {
+                Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
+                        + " AppWidget provider '" + component + '\'');
+                return null;
+            }
+
+            p = new Provider();
+            AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo();
+            info.provider = component;
+            p.uid = activityInfo.applicationInfo.uid;
+
+            Resources res = mPackageManager
+                    .getResourcesForApplication(activityInfo.applicationInfo);
+
+            TypedArray sa = res.obtainAttributes(attrs,
+                    com.android.internal.R.styleable.AppWidgetProviderInfo);
+
+            // These dimensions has to be resolved in the application's context.
+            // We simply send back the raw complex data, which will be
+            // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
+            TypedValue value = sa
+                    .peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
+            info.minWidth = value != null ? value.data : 0;
+            value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
+            info.minHeight = value != null ? value.data : 0;
+            value = sa.peekValue(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth);
+            info.minResizeWidth = value != null ? value.data : info.minWidth;
+            value = sa.peekValue(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight);
+            info.minResizeHeight = value != null ? value.data : info.minHeight;
+            info.updatePeriodMillis = sa.getInt(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
+            info.initialLayout = sa.getResourceId(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
+            String className = sa
+                    .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
+            if (className != null) {
+                info.configure = new ComponentName(component.getPackageName(), className);
+            }
+            info.label = activityInfo.loadLabel(mPackageManager).toString();
+            info.icon = ri.getIconResource();
+            info.previewImage = sa.getResourceId(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
+            info.autoAdvanceViewId = sa.getResourceId(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
+            info.resizeMode = sa.getInt(
+                    com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
+                    AppWidgetProviderInfo.RESIZE_NONE);
+
+            sa.recycle();
+        } catch (Exception e) {
+            // Ok to catch Exception here, because anything going wrong because
+            // of what a client process passes to us should not be fatal for the
+            // system process.
+            Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e);
+            return null;
+        } finally {
+            if (parser != null)
+                parser.close();
+        }
+        return p;
+    }
+
+    int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException {
+        PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0);
+        if (pkgInfo == null || pkgInfo.applicationInfo == null) {
+            throw new PackageManager.NameNotFoundException();
+        }
+        return pkgInfo.applicationInfo.uid;
+    }
+
+    int enforceCallingUid(String packageName) throws IllegalArgumentException {
+        int callingUid = Binder.getCallingUid();
+        int packageUid;
+        try {
+            packageUid = getUidForPackage(packageName);
+        } catch (PackageManager.NameNotFoundException ex) {
+            throw new IllegalArgumentException("packageName and uid don't match packageName="
+                    + packageName);
+        }
+        if (!UserId.isSameApp(callingUid, packageUid)) {
+            throw new IllegalArgumentException("packageName and uid don't match packageName="
+                    + packageName);
+        }
+        return callingUid;
+    }
+
+    void sendInitialBroadcasts() {
+        synchronized (mAppWidgetIds) {
+            ensureStateLoadedLocked();
+            final int N = mInstalledProviders.size();
+            for (int i = 0; i < N; i++) {
+                Provider p = mInstalledProviders.get(i);
+                if (p.instances.size() > 0) {
+                    sendEnableIntentLocked(p);
+                    int[] appWidgetIds = getAppWidgetIds(p);
+                    sendUpdateIntentLocked(p, appWidgetIds);
+                    registerForBroadcastsLocked(p, appWidgetIds);
+                }
+            }
+        }
+    }
+
+    // only call from initialization -- it assumes that the data structures are all empty
+    void loadStateLocked() {
+        AtomicFile file = savedStateFile();
+        try {
+            FileInputStream stream = file.openRead();
+            readStateFromFileLocked(stream);
+
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (IOException e) {
+                    Slog.w(TAG, "Failed to close state FileInputStream " + e);
+                }
+            }
+        } catch (FileNotFoundException e) {
+            Slog.w(TAG, "Failed to read state: " + e);
+        }
+    }
+
+    void saveStateLocked() {
+        AtomicFile file = savedStateFile();
+        FileOutputStream stream;
+        try {
+            stream = file.startWrite();
+            if (writeStateToFileLocked(stream)) {
+                file.finishWrite(stream);
+            } else {
+                file.failWrite(stream);
+                Slog.w(TAG, "Failed to save state, restoring backup.");
+            }
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed open state file for write: " + e);
+        }
+    }
+
+    boolean writeStateToFileLocked(FileOutputStream stream) {
+        int N;
+
+        try {
+            XmlSerializer out = new FastXmlSerializer();
+            out.setOutput(stream, "utf-8");
+            out.startDocument(null, true);
+            out.startTag(null, "gs");
+
+            int providerIndex = 0;
+            N = mInstalledProviders.size();
+            for (int i = 0; i < N; i++) {
+                Provider p = mInstalledProviders.get(i);
+                if (p.instances.size() > 0) {
+                    out.startTag(null, "p");
+                    out.attribute(null, "pkg", p.info.provider.getPackageName());
+                    out.attribute(null, "cl", p.info.provider.getClassName());
+                    out.endTag(null, "p");
+                    p.tag = providerIndex;
+                    providerIndex++;
+                }
+            }
+
+            N = mHosts.size();
+            for (int i = 0; i < N; i++) {
+                Host host = mHosts.get(i);
+                out.startTag(null, "h");
+                out.attribute(null, "pkg", host.packageName);
+                out.attribute(null, "id", Integer.toHexString(host.hostId));
+                out.endTag(null, "h");
+                host.tag = i;
+            }
+
+            N = mAppWidgetIds.size();
+            for (int i = 0; i < N; i++) {
+                AppWidgetId id = mAppWidgetIds.get(i);
+                out.startTag(null, "g");
+                out.attribute(null, "id", Integer.toHexString(id.appWidgetId));
+                out.attribute(null, "h", Integer.toHexString(id.host.tag));
+                if (id.provider != null) {
+                    out.attribute(null, "p", Integer.toHexString(id.provider.tag));
+                }
+                out.endTag(null, "g");
+            }
+
+            out.endTag(null, "gs");
+
+            out.endDocument();
+            return true;
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to write state: " + e);
+            return false;
+        }
+    }
+
+    void readStateFromFileLocked(FileInputStream stream) {
+        boolean success = false;
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, null);
+
+            int type;
+            int providerIndex = 0;
+            HashMap<Integer, Provider> loadedProviders = new HashMap<Integer, Provider>();
+            do {
+                type = parser.next();
+                if (type == XmlPullParser.START_TAG) {
+                    String tag = parser.getName();
+                    if ("p".equals(tag)) {
+                        // TODO: do we need to check that this package has the same signature
+                        // as before?
+                        String pkg = parser.getAttributeValue(null, "pkg");
+                        String cl = parser.getAttributeValue(null, "cl");
+
+                        final PackageManager packageManager = mContext.getPackageManager();
+                        try {
+                            packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0);
+                        } catch (PackageManager.NameNotFoundException e) {
+                            String[] pkgs = packageManager
+                                    .currentToCanonicalPackageNames(new String[] { pkg });
+                            pkg = pkgs[0];
+                        }
+
+                        Provider p = lookupProviderLocked(new ComponentName(pkg, cl));
+                        if (p == null && mSafeMode) {
+                            // if we're in safe mode, make a temporary one
+                            p = new Provider();
+                            p.info = new AppWidgetProviderInfo();
+                            p.info.provider = new ComponentName(pkg, cl);
+                            p.zombie = true;
+                            mInstalledProviders.add(p);
+                        }
+                        if (p != null) {
+                            // if it wasn't uninstalled or something
+                            loadedProviders.put(providerIndex, p);
+                        }
+                        providerIndex++;
+                    } else if ("h".equals(tag)) {
+                        Host host = new Host();
+
+                        // TODO: do we need to check that this package has the same signature
+                        // as before?
+                        host.packageName = parser.getAttributeValue(null, "pkg");
+                        try {
+                            host.uid = getUidForPackage(host.packageName);
+                        } catch (PackageManager.NameNotFoundException ex) {
+                            host.zombie = true;
+                        }
+                        if (!host.zombie || mSafeMode) {
+                            // In safe mode, we don't discard the hosts we don't recognize
+                            // so that they're not pruned from our list. Otherwise, we do.
+                            host.hostId = Integer
+                                    .parseInt(parser.getAttributeValue(null, "id"), 16);
+                            mHosts.add(host);
+                        }
+                    } else if ("g".equals(tag)) {
+                        AppWidgetId id = new AppWidgetId();
+                        id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16);
+                        if (id.appWidgetId >= mNextAppWidgetId) {
+                            mNextAppWidgetId = id.appWidgetId + 1;
+                        }
+
+                        String providerString = parser.getAttributeValue(null, "p");
+                        if (providerString != null) {
+                            // there's no provider if it hasn't been bound yet.
+                            // maybe we don't have to save this, but it brings the system
+                            // to the state it was in.
+                            int pIndex = Integer.parseInt(providerString, 16);
+                            id.provider = loadedProviders.get(pIndex);
+                            if (false) {
+                                Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider "
+                                        + pIndex + " which is " + id.provider);
+                            }
+                            if (id.provider == null) {
+                                // This provider is gone. We just let the host figure out
+                                // that this happened when it fails to load it.
+                                continue;
+                            }
+                        }
+
+                        int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16);
+                        id.host = mHosts.get(hIndex);
+                        if (id.host == null) {
+                            // This host is gone.
+                            continue;
+                        }
+
+                        if (id.provider != null) {
+                            id.provider.instances.add(id);
+                        }
+                        id.host.instances.add(id);
+                        mAppWidgetIds.add(id);
+                    }
+                }
+            } while (type != XmlPullParser.END_DOCUMENT);
+            success = true;
+        } catch (NullPointerException e) {
+            Slog.w(TAG, "failed parsing " + e);
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "failed parsing " + e);
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "failed parsing " + e);
+        } catch (IOException e) {
+            Slog.w(TAG, "failed parsing " + e);
+        } catch (IndexOutOfBoundsException e) {
+            Slog.w(TAG, "failed parsing " + e);
+        }
+
+        if (success) {
+            // delete any hosts that didn't manage to get connected (should happen)
+            // if it matters, they'll be reconnected.
+            for (int i = mHosts.size() - 1; i >= 0; i--) {
+                pruneHostLocked(mHosts.get(i));
+            }
+        } else {
+            // failed reading, clean up
+            Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
+
+            mAppWidgetIds.clear();
+            mHosts.clear();
+            final int N = mInstalledProviders.size();
+            for (int i = 0; i < N; i++) {
+                mInstalledProviders.get(i).instances.clear();
+            }
+        }
+    }
+
+    AtomicFile savedStateFile() {
+        int userId = UserId.getCallingUserId();
+        File dir = new File("/data/system/users/" + userId);
+        File settingsFile = new File(dir, SETTINGS_FILENAME);
+        if (!dir.exists()) {
+            dir.mkdirs();
+            if (userId == 0) {
+                // Migrate old data
+                File oldFile = new File("/data/system/" + SETTINGS_FILENAME);
+                // Method doesn't throw an exception on failure. Ignore any errors
+                // in moving the file (like non-existence)
+                oldFile.renameTo(settingsFile);
+            }
+        }
+        return new AtomicFile(settingsFile);
+    }
+
+    void addProvidersForPackageLocked(String pkgName) {
+        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+        intent.setPackage(pkgName);
+        List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
+                PackageManager.GET_META_DATA);
+
+        final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
+        for (int i = 0; i < N; i++) {
+            ResolveInfo ri = broadcastReceivers.get(i);
+            ActivityInfo ai = ri.activityInfo;
+            if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+                continue;
+            }
+            if (pkgName.equals(ai.packageName)) {
+                addProviderLocked(ri);
+            }
+        }
+    }
+
+    void updateProvidersForPackageLocked(String pkgName) {
+        HashSet<String> keep = new HashSet<String>();
+        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+        intent.setPackage(pkgName);
+        List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
+                PackageManager.GET_META_DATA);
+
+        // add the missing ones and collect which ones to keep
+        int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
+        for (int i = 0; i < N; i++) {
+            ResolveInfo ri = broadcastReceivers.get(i);
+            ActivityInfo ai = ri.activityInfo;
+            if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+                continue;
+            }
+            if (pkgName.equals(ai.packageName)) {
+                ComponentName component = new ComponentName(ai.packageName, ai.name);
+                Provider p = lookupProviderLocked(component);
+                if (p == null) {
+                    if (addProviderLocked(ri)) {
+                        keep.add(ai.name);
+                    }
+                } else {
+                    Provider parsed = parseProviderInfoXml(component, ri);
+                    if (parsed != null) {
+                        keep.add(ai.name);
+                        // Use the new AppWidgetProviderInfo.
+                        p.info = parsed.info;
+                        // If it's enabled
+                        final int M = p.instances.size();
+                        if (M > 0) {
+                            int[] appWidgetIds = getAppWidgetIds(p);
+                            // Reschedule for the new updatePeriodMillis (don't worry about handling
+                            // it specially if updatePeriodMillis didn't change because we just sent
+                            // an update, and the next one will be updatePeriodMillis from now).
+                            cancelBroadcasts(p);
+                            registerForBroadcastsLocked(p, appWidgetIds);
+                            // If it's currently showing, call back with the new
+                            // AppWidgetProviderInfo.
+                            for (int j = 0; j < M; j++) {
+                                AppWidgetId id = p.instances.get(j);
+                                id.views = null;
+                                if (id.host != null && id.host.callbacks != null) {
+                                    try {
+                                        id.host.callbacks.providerChanged(id.appWidgetId, p.info);
+                                    } catch (RemoteException ex) {
+                                        // It failed; remove the callback. No need to prune because
+                                        // we know that this host is still referenced by this
+                                        // instance.
+                                        id.host.callbacks = null;
+                                    }
+                                }
+                            }
+                            // Now that we've told the host, push out an update.
+                            sendUpdateIntentLocked(p, appWidgetIds);
+                        }
+                    }
+                }
+            }
+        }
+
+        // prune the ones we don't want to keep
+        N = mInstalledProviders.size();
+        for (int i = N - 1; i >= 0; i--) {
+            Provider p = mInstalledProviders.get(i);
+            if (pkgName.equals(p.info.provider.getPackageName())
+                    && !keep.contains(p.info.provider.getClassName())) {
+                removeProviderLocked(i, p);
+            }
+        }
+    }
+
+    void removeProvidersForPackageLocked(String pkgName) {
+        int N = mInstalledProviders.size();
+        for (int i = N - 1; i >= 0; i--) {
+            Provider p = mInstalledProviders.get(i);
+            if (pkgName.equals(p.info.provider.getPackageName())) {
+                removeProviderLocked(i, p);
+            }
+        }
+
+        // Delete the hosts for this package too
+        //
+        // By now, we have removed any AppWidgets that were in any hosts here,
+        // so we don't need to worry about sending DISABLE broadcasts to them.
+        N = mHosts.size();
+        for (int i = N - 1; i >= 0; i--) {
+            Host host = mHosts.get(i);
+            if (pkgName.equals(host.packageName)) {
+                deleteHostLocked(host);
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 31515e1..a7b08f5 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1675,7 +1675,8 @@
         synchronized(mClearDataLock) {
             mClearingData = true;
             try {
-                mActivityManager.clearApplicationUserData(packageName, observer);
+                mActivityManager.clearApplicationUserData(packageName, observer,
+                        Binder.getOrigCallingUser());
             } catch (RemoteException e) {
                 // can't happen because the activity manager is in this process
             }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index b7dc4a2..eab60a7 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -992,11 +992,15 @@
                 NetworkInfo ni = network.getNetworkInfo();
 
                 if (ni.isAvailable() == false) {
-                    if (DBG) log("special network not available");
                     if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
+                        if (DBG) log("special network not available ni=" + ni.getTypeName());
                         return Phone.APN_TYPE_NOT_AVAILABLE;
                     } else {
                         // else make the attempt anyway - probably giving REQUEST_STARTED below
+                        if (DBG) {
+                            log("special network not available, but try anyway ni=" +
+                                    ni.getTypeName());
+                        }
                     }
                 }
 
@@ -1390,9 +1394,7 @@
     private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
         @Override
         public void onUidRulesChanged(int uid, int uidRules) {
-            // only someone like NPMS should only be calling us
-            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-
+            // caller is NPMS, since we only register with them
             if (LOGD_RULES) {
                 log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
             }
@@ -1411,9 +1413,7 @@
 
         @Override
         public void onMeteredIfacesChanged(String[] meteredIfaces) {
-            // only someone like NPMS should only be calling us
-            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-
+            // caller is NPMS, since we only register with them
             if (LOGD_RULES) {
                 log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
             }
@@ -1425,6 +1425,27 @@
                 }
             }
         }
+
+        @Override
+        public void onRestrictBackgroundChanged(boolean restrictBackground) {
+            // caller is NPMS, since we only register with them
+            if (LOGD_RULES) {
+                log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
+            }
+
+            // kick off connectivity change broadcast for active network, since
+            // global background policy change is radical.
+            final int networkType = mActiveDefaultNetwork;
+            if (isNetworkTypeValid(networkType)) {
+                final NetworkStateTracker tracker = mNetTrackers[networkType];
+                if (tracker != null) {
+                    final NetworkInfo info = tracker.getNetworkInfo();
+                    if (info != null && info.isConnected()) {
+                        sendConnectedBroadcast(info);
+                    }
+                }
+            }
+        }
     };
 
     /**
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 4dad209..0bcec2e 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -142,5 +142,5 @@
 # ---------------------------
 # NetworkStatsService.java
 # ---------------------------
-51100 netstats_mobile_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3),(dev_history_start|2|3)
-51101 netstats_wifi_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3),(dev_history_start|2|3)
+51100 netstats_mobile_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
+51101 netstats_wifi_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index aba1bc6..86669f8 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -101,6 +101,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -154,6 +155,7 @@
     final IWindowManager mIWindowManager;
     final HandlerCaller mCaller;
     private final InputMethodFileManager mFileManager;
+    private final InputMethodAndSubtypeListManager mImListManager;
 
     final InputBindResult mNoBinding = new InputBindResult(null, null, -1);
 
@@ -555,6 +557,7 @@
         synchronized (mMethodMap) {
             mFileManager = new InputMethodFileManager(mMethodMap);
         }
+        mImListManager = new InputMethodAndSubtypeListManager(context, this);
 
         (new MyPackageMonitor()).register(mContext, true);
 
@@ -1693,6 +1696,19 @@
     }
 
     @Override
+    public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
+        synchronized (mMethodMap) {
+            final ImeSubtypeListItem nextSubtype = mImListManager.getNextInputMethod(
+                    onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
+            if (nextSubtype == null) {
+                return false;
+            }
+            setInputMethodWithSubtypeId(token, nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
+            return true;
+        }
+    }
+
+    @Override
     public InputMethodSubtype getLastInputMethodSubtype() {
         synchronized (mMethodMap) {
             final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
@@ -2109,62 +2125,9 @@
 
             hideInputMethodMenuLocked();
 
-            final TreeMap<InputMethodInfo, List<InputMethodSubtype>> sortedImmis =
-                    new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
-                            new Comparator<InputMethodInfo>() {
-                                @Override
-                                public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
-                                    if (imi2 == null) return 0;
-                                    if (imi1 == null) return 1;
-                                    if (pm == null) {
-                                        return imi1.getId().compareTo(imi2.getId());
-                                    }
-                                    CharSequence imiId1 = imi1.loadLabel(pm) + "/" + imi1.getId();
-                                    CharSequence imiId2 = imi2.loadLabel(pm) + "/" + imi2.getId();
-                                    return imiId1.toString().compareTo(imiId2.toString());
-                                }
-                            });
-
-            sortedImmis.putAll(immis);
-
-            final ArrayList<ImeSubtypeListItem> imList = new ArrayList<ImeSubtypeListItem>();
-
-            for (InputMethodInfo imi : sortedImmis.keySet()) {
-                if (imi == null) continue;
-                List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
-                HashSet<String> enabledSubtypeSet = new HashSet<String>();
-                for (InputMethodSubtype subtype: explicitlyOrImplicitlyEnabledSubtypeList) {
-                    enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
-                }
-                ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
-                final CharSequence imeLabel = imi.loadLabel(pm);
-                if (showSubtypes && enabledSubtypeSet.size() > 0) {
-                    final int subtypeCount = imi.getSubtypeCount();
-                    if (DEBUG) {
-                        Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
-                    }
-                    for (int j = 0; j < subtypeCount; ++j) {
-                        final InputMethodSubtype subtype = imi.getSubtypeAt(j);
-                        final String subtypeHashCode = String.valueOf(subtype.hashCode());
-                        // We show all enabled IMEs and subtypes when an IME is shown.
-                        if (enabledSubtypeSet.contains(subtypeHashCode)
-                                && ((mInputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
-                            final CharSequence subtypeLabel =
-                                    subtype.overridesImplicitlyEnabledSubtype() ? null
-                                            : subtype.getDisplayName(context, imi.getPackageName(),
-                                                    imi.getServiceInfo().applicationInfo);
-                            imList.add(new ImeSubtypeListItem(imeLabel, subtypeLabel, imi, j));
-
-                            // Removing this subtype from enabledSubtypeSet because we no longer
-                            // need to add an entry of this subtype to imList to avoid duplicated
-                            // entries.
-                            enabledSubtypeSet.remove(subtypeHashCode);
-                        }
-                    }
-                } else {
-                    imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID));
-                }
-            }
+            final List<ImeSubtypeListItem> imList =
+                    mImListManager.getSortedInputMethodAndSubtypeList(
+                            showSubtypes, mInputShown, isScreenLocked);
 
             if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
                 final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtype();
@@ -2786,6 +2749,117 @@
         }
     }
 
+    private static class InputMethodAndSubtypeListManager {
+        private final Context mContext;
+        private final PackageManager mPm;
+        private final InputMethodManagerService mImms;
+        public InputMethodAndSubtypeListManager(Context context, InputMethodManagerService imms) {
+            mContext = context;
+            mPm = context.getPackageManager();
+            mImms = imms;
+        }
+
+        private final TreeMap<InputMethodInfo, List<InputMethodSubtype>> mSortedImmis =
+                new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
+                        new Comparator<InputMethodInfo>() {
+                            @Override
+                            public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
+                                if (imi2 == null) return 0;
+                                if (imi1 == null) return 1;
+                                if (mPm == null) {
+                                    return imi1.getId().compareTo(imi2.getId());
+                                }
+                                CharSequence imiId1 = imi1.loadLabel(mPm) + "/" + imi1.getId();
+                                CharSequence imiId2 = imi2.loadLabel(mPm) + "/" + imi2.getId();
+                                return imiId1.toString().compareTo(imiId2.toString());
+                            }
+                        });
+
+        public ImeSubtypeListItem getNextInputMethod(
+                boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
+            if (imi == null) {
+                return null;
+            }
+            final List<ImeSubtypeListItem> imList = getSortedInputMethodAndSubtypeList();
+            if (imList.size() <= 1) {
+                return null;
+            }
+            final int N = imList.size();
+            final int currentSubtypeId = subtype != null
+                    ? mImms.getSubtypeIdFromHashCode(imi, subtype.hashCode())
+                    : NOT_A_SUBTYPE_ID;
+            for (int i = 0; i < N; ++i) {
+                final ImeSubtypeListItem isli = imList.get(i);
+                if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
+                    if (!onlyCurrentIme) {
+                        return imList.get((i + 1) % N);
+                    }
+                    for (int j = 0; j < N - 1; ++j) {
+                        final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
+                        if (candidate.mImi.equals(imi)) {
+                            return candidate;
+                        }
+                    }
+                    return null;
+                }
+            }
+            return null;
+        }
+
+        public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
+            return getSortedInputMethodAndSubtypeList(true, false, false);
+        }
+
+        public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(boolean showSubtypes,
+                boolean inputShown, boolean isScreenLocked) {
+            final ArrayList<ImeSubtypeListItem> imList = new ArrayList<ImeSubtypeListItem>();
+            final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
+                    mImms.getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked();
+            if (immis == null || immis.size() == 0) {
+                return Collections.emptyList();
+            }
+            mSortedImmis.clear();
+            mSortedImmis.putAll(immis);
+            for (InputMethodInfo imi : mSortedImmis.keySet()) {
+                if (imi == null) continue;
+                List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
+                HashSet<String> enabledSubtypeSet = new HashSet<String>();
+                for (InputMethodSubtype subtype: explicitlyOrImplicitlyEnabledSubtypeList) {
+                    enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
+                }
+                ArrayList<InputMethodSubtype> subtypes = getSubtypes(imi);
+                final CharSequence imeLabel = imi.loadLabel(mPm);
+                if (showSubtypes && enabledSubtypeSet.size() > 0) {
+                    final int subtypeCount = imi.getSubtypeCount();
+                    if (DEBUG) {
+                        Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
+                    }
+                    for (int j = 0; j < subtypeCount; ++j) {
+                        final InputMethodSubtype subtype = imi.getSubtypeAt(j);
+                        final String subtypeHashCode = String.valueOf(subtype.hashCode());
+                        // We show all enabled IMEs and subtypes when an IME is shown.
+                        if (enabledSubtypeSet.contains(subtypeHashCode)
+                                && ((inputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
+                            final CharSequence subtypeLabel =
+                                    subtype.overridesImplicitlyEnabledSubtype() ? null
+                                            : subtype.getDisplayName(mContext, imi.getPackageName(),
+                                                    imi.getServiceInfo().applicationInfo);
+                            imList.add(new ImeSubtypeListItem(imeLabel, subtypeLabel, imi, j));
+
+                            // Removing this subtype from enabledSubtypeSet because we no longer
+                            // need to add an entry of this subtype to imList to avoid duplicated
+                            // entries.
+                            enabledSubtypeSet.remove(subtypeHashCode);
+                        }
+                    }
+                } else {
+                    imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID));
+                }
+            }
+            return imList;
+        }
+    }
+
     /**
      * Utility class for putting and getting settings for InputMethod
      * TODO: Move all putters and getters of settings to this class.
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 56afe7f..8cb9d99b 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1962,8 +1962,10 @@
                 } else {
                     mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
                 }
-                NetworkInfo info =
-                    (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+
+                final ConnectivityManager connManager = (ConnectivityManager) context
+                        .getSystemService(Context.CONNECTIVITY_SERVICE);
+                final NetworkInfo info = connManager.getActiveNetworkInfo();
 
                 // Notify location providers of current network state
                 synchronized (mLock) {
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index f475dd6..308661f 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -153,6 +153,10 @@
                         start = i + 1;
                     }
                 }
+                if (start == 0) {
+                    final String rawEvent = new String(buffer, start, count, Charsets.UTF_8);
+                    log("RCV incomplete <- {" + rawEvent + "}");
+                }
 
                 // We should end at the amount we read. If not, compact then
                 // buffer and read again.
@@ -297,7 +301,11 @@
             throws NativeDaemonConnectorException {
         final ArrayList<NativeDaemonEvent> events = Lists.newArrayList();
 
-        mResponseQueue.clear();
+        while (mResponseQueue.size() > 0) {
+            try {
+                log("ignoring {" + mResponseQueue.take() + "}");
+            } catch (Exception e) {}
+        }
 
         final String sentCommand = sendCommandLocked(cmd, args);
 
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index f7fe39e..1ff914f 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -55,7 +55,7 @@
 
     private static final int EVENT_AUTO_TIME_CHANGED = 1;
     private static final int EVENT_POLL_NETWORK_TIME = 2;
-    private static final int EVENT_WIFI_CONNECTED = 3;
+    private static final int EVENT_NETWORK_CONNECTED = 3;
 
     /** Normal polling frequency */
     private static final long POLLING_INTERVAL_MS = 24L * 60 * 60 * 1000; // 24 hrs
@@ -234,13 +234,15 @@
             String action = intent.getAction();
             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
                 // There is connectivity
-                NetworkInfo netInfo = (NetworkInfo)intent.getParcelableExtra(
-                        ConnectivityManager.EXTRA_NETWORK_INFO);
+                final ConnectivityManager connManager = (ConnectivityManager) context
+                        .getSystemService(Context.CONNECTIVITY_SERVICE);
+                final NetworkInfo netInfo = connManager.getActiveNetworkInfo();
                 if (netInfo != null) {
                     // Verify that it's a WIFI connection
                     if (netInfo.getState() == NetworkInfo.State.CONNECTED &&
-                            netInfo.getType() == ConnectivityManager.TYPE_WIFI ) {
-                        mHandler.obtainMessage(EVENT_WIFI_CONNECTED).sendToTarget();
+                            (netInfo.getType() == ConnectivityManager.TYPE_WIFI ||
+                                netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) ) {
+                        mHandler.obtainMessage(EVENT_NETWORK_CONNECTED).sendToTarget();
                     }
                 }
             }
@@ -259,7 +261,7 @@
             switch (msg.what) {
                 case EVENT_AUTO_TIME_CHANGED:
                 case EVENT_POLL_NETWORK_TIME:
-                case EVENT_WIFI_CONNECTED:
+                case EVENT_NETWORK_CONNECTED:
                     onPollNetworkTime(msg.what);
                     break;
             }
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 5039294..b3eceb1 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -45,6 +45,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserId;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
@@ -767,7 +768,9 @@
                     long identity = Binder.clearCallingIdentity();
                     try {
                         r.statusBarKey = mStatusBar.addNotification(n);
-                        mAttentionLight.pulse();
+                        if ((n.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
+                            mAttentionLight.pulse();
+                        }
                     }
                     finally {
                         Binder.restoreCallingIdentity(identity);
@@ -1034,7 +1037,7 @@
         try {
             ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
                     pkg, 0);
-            if (ai.uid != uid) {
+            if (!UserId.isSameApp(ai.uid, uid)) {
                 throw new SecurityException("Calling uid " + uid + " gave package"
                         + pkg + " which is owned by uid " + ai.uid);
             }
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index bb0ac3e..e953355 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -50,6 +50,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.EventLog;
@@ -176,6 +177,7 @@
 
     private boolean mDoneBooting = false;
     private boolean mBootCompleted = false;
+    private boolean mHeadless = false;
     private int mStayOnConditions = 0;
     private final int[] mBroadcastQueue = new int[] { -1, -1, -1 };
     private final int[] mBroadcastWhy = new int[3];
@@ -530,6 +532,7 @@
         mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS);
         mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD);
         mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
+        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
 
         nativeInit();
         synchronized (mLocks) {
@@ -1894,9 +1897,11 @@
     }
 
     private void updateNativePowerStateLocked() {
-        nativeSetPowerState(
-                (mPowerState & SCREEN_ON_BIT) != 0,
-                (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+        if (!mHeadless) {
+            nativeSetPowerState(
+                    (mPowerState & SCREEN_ON_BIT) != 0,
+                    (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+        }
     }
 
     private int screenOffFinishedAnimatingLocked(int reason) {
@@ -2240,11 +2245,13 @@
                         mScreenOffHandler.postAtTime(this, now+(1000/60));
                     }
                 } else {
-                    // It's pretty scary to hold mLocks for this long, and we should
-                    // redesign this, but it works for now.
-                    nativeStartSurfaceFlingerAnimation(
-                            mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
-                            ? 0 : mAnimationSetting);
+                    if (!mHeadless) {
+                        // It's pretty scary to hold mLocks for this long, and we should
+                        // redesign this, but it works for now.
+                        nativeStartSurfaceFlingerAnimation(
+                                mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
+                                ? 0 : mAnimationSetting);
+                    }
                     mScreenBrightness.jumpToTargetLocked();
                 }
             }
diff --git a/services/java/com/android/server/SerialService.java b/services/java/com/android/server/SerialService.java
new file mode 100644
index 0000000..5d2b2a0
--- /dev/null
+++ b/services/java/com/android/server/SerialService.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions an
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.hardware.ISerialManager;
+import android.os.ParcelFileDescriptor;
+
+import java.io.File;
+import java.util.ArrayList;
+
+public class SerialService extends ISerialManager.Stub {
+
+    private final Context mContext;
+    private final String[] mSerialPorts;
+
+    public SerialService(Context context) {
+        mContext = context;
+        mSerialPorts = context.getResources().getStringArray(
+                com.android.internal.R.array.config_serialPorts);
+    }
+
+    public String[] getSerialPorts() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);
+
+        ArrayList<String> ports = new ArrayList<String>();
+        for (int i = 0; i < mSerialPorts.length; i++) {
+            String path = mSerialPorts[i];
+            if (new File(path).exists()) {
+                ports.add(path);
+            }
+        }
+        String[] result = new String[ports.size()];
+        ports.toArray(result);
+        return result;
+    }
+
+    public ParcelFileDescriptor openSerialPort(String path) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);
+        return native_open(path);
+    }
+
+    private native ParcelFileDescriptor native_open(String path);
+}
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index da97089..a7a583c 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -44,12 +44,16 @@
     private static final String WALLPAPER_IMAGE_FILENAME = "wallpaper";
     private static final String WALLPAPER_INFO_FILENAME = "wallpaper_info.xml";
 
-    private static final String WALLPAPER_IMAGE_DIR = "/data/data/com.android.settings/files";
-    private static final String WALLPAPER_IMAGE = WALLPAPER_IMAGE_DIR + "/" + WALLPAPER_IMAGE_FILENAME;
+    // TODO: Will need to change if backing up non-primary user's wallpaper
+    private static final String WALLPAPER_IMAGE_DIR = "/data/system/users/0";
+    private static final String WALLPAPER_IMAGE = WallpaperBackupHelper.WALLPAPER_IMAGE;
 
-    private static final String WALLPAPER_INFO_DIR = "/data/system";
-    private static final String WALLPAPER_INFO = WALLPAPER_INFO_DIR + "/" +  WALLPAPER_INFO_FILENAME;
-
+    // TODO: Will need to change if backing up non-primary user's wallpaper
+    private static final String WALLPAPER_INFO_DIR = "/data/system/users/0";
+    private static final String WALLPAPER_INFO = WallpaperBackupHelper.WALLPAPER_INFO;
+    // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
+    private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
+    private static final String WALLPAPER_INFO_KEY = WallpaperBackupHelper.WALLPAPER_INFO_KEY;
 
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
@@ -58,13 +62,15 @@
         WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
                 Context.WALLPAPER_SERVICE);
         String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
-        if (wallpaper != null && wallpaper.mName != null && wallpaper.mName.length() > 0) {
+        String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
+        if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) {
             // When the wallpaper has a name, back up the info by itself.
             // TODO: Don't rely on the innards of the service object like this!
             // TODO: Send a delete for any stored wallpaper image in this case?
             files = new String[] { WALLPAPER_INFO };
+            keys = new String[] { WALLPAPER_INFO_KEY };
         }
-        addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files));
+        addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
         super.onBackup(oldState, data, newState);
     }
 
@@ -90,9 +96,11 @@
             throws IOException {
         // On restore, we also support a previous data schema "system_files"
         addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this,
-                new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
+                new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
+                new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} ));
         addHelper("system_files", new WallpaperBackupHelper(SystemBackupAgent.this,
-                new String[] { WALLPAPER_IMAGE }));
+                new String[] { WALLPAPER_IMAGE },
+                new String[] { WALLPAPER_IMAGE_KEY} ));
 
         try {
             super.onRestore(data, appVersionCode, newState);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 762acbb..0dbc7c3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,6 +108,7 @@
         String factoryTestStr = SystemProperties.get("ro.factorytest");
         int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
                 : Integer.parseInt(factoryTestStr);
+        final boolean headless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
 
         LightsService lights = null;
         PowerManagerService power = null;
@@ -126,6 +127,7 @@
         BluetoothA2dpService bluetoothA2dp = null;
         DockObserver dock = null;
         UsbService usb = null;
+        SerialService serial = null;
         UiModeManagerService uiMode = null;
         RecognitionManagerService recognition = null;
         ThrottleService throttle = null;
@@ -231,10 +233,13 @@
                 bluetooth = new BluetoothService(context);
                 ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth);
                 bluetooth.initAfterRegistration();
-                bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
-                ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
-                                          bluetoothA2dp);
-                bluetooth.initAfterA2dpRegistration();
+
+                if (!"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
+                    bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
+                    ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
+                                              bluetoothA2dp);
+                    bluetooth.initAfterA2dpRegistration();
+                }
 
                 int airplaneModeOn = Settings.System.getInt(mContentResolver,
                         Settings.System.AIRPLANE_MODE_ON, 0);
@@ -396,15 +401,17 @@
                 reportWtf("starting ThrottleService", e);
             }
 
-            try {
-                /*
-                 * NotificationManagerService is dependant on MountService,
-                 * (for media / usb notifications) so we must start MountService first.
-                 */
-                Slog.i(TAG, "Mount Service");
-                ServiceManager.addService("mount", new MountService(context));
-            } catch (Throwable e) {
-                reportWtf("starting Mount Service", e);
+            if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+                try {
+                    /*
+                     * NotificationManagerService is dependant on MountService,
+                     * (for media / usb notifications) so we must start MountService first.
+                     */
+                    Slog.i(TAG, "Mount Service");
+                    ServiceManager.addService("mount", new MountService(context));
+                } catch (Throwable e) {
+                    reportWtf("starting Mount Service", e);
+                }
             }
 
             try {
@@ -456,19 +463,26 @@
                 reportWtf("starting DropBoxManagerService", e);
             }
 
-            try {
-                Slog.i(TAG, "Wallpaper Service");
-                wallpaper = new WallpaperManagerService(context);
-                ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
-            } catch (Throwable e) {
-                reportWtf("starting Wallpaper Service", e);
+            if (context.getResources().getBoolean(
+                        com.android.internal.R.bool.config_enableWallpaperService)) {
+                try {
+                    Slog.i(TAG, "Wallpaper Service");
+                    if (!headless) {
+                        wallpaper = new WallpaperManagerService(context);
+                        ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
+                    }
+                } catch (Throwable e) {
+                    reportWtf("starting Wallpaper Service", e);
+                }
             }
 
-            try {
-                Slog.i(TAG, "Audio Service");
-                ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
-            } catch (Throwable e) {
-                reportWtf("starting Audio Service", e);
+            if (!"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
+                try {
+                    Slog.i(TAG, "Audio Service");
+                    ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
+                } catch (Throwable e) {
+                    reportWtf("starting Audio Service", e);
+                }
             }
 
             try {
@@ -497,6 +511,15 @@
             }
 
             try {
+                Slog.i(TAG, "Serial Service");
+                // Serial port support
+                serial = new SerialService(context);
+                ServiceManager.addService(Context.SERIAL_SERVICE, serial);
+            } catch (Throwable e) {
+                Slog.e(TAG, "Failure starting SerialService", e);
+            }
+
+            try {
                 Slog.i(TAG, "UI Mode Manager Service");
                 // Listen for UI mode changes
                 uiMode = new UiModeManagerService(context);
@@ -642,7 +665,7 @@
             public void run() {
                 Slog.i(TAG, "Making services ready");
 
-                startSystemUi(contextF);
+                if (!headless) startSystemUi(contextF);
                 try {
                     if (batteryF != null) batteryF.systemReady();
                 } catch (Throwable e) {
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 4925a4e..8ee12bc 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -24,6 +24,7 @@
 import android.app.PendingIntent;
 import android.app.WallpaperInfo;
 import android.app.backup.BackupManager;
+import android.app.backup.WallpaperBackupHelper;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -43,11 +44,13 @@
 import android.os.RemoteCallbackList;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserId;
 import android.service.wallpaper.IWallpaperConnection;
 import android.service.wallpaper.IWallpaperEngine;
 import android.service.wallpaper.IWallpaperService;
 import android.service.wallpaper.WallpaperService;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.Xml;
 import android.view.Display;
 import android.view.IWindowManager;
@@ -70,6 +73,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
+import com.android.server.am.ActivityManagerService;
 
 class WallpaperManagerService extends IWallpaperManager.Stub {
     static final String TAG = "WallpaperService";
@@ -83,17 +87,9 @@
      */
     static final long MIN_WALLPAPER_CRASH_TIME = 10000;
     
-    static final File WALLPAPER_DIR = new File(
-            "/data/data/com.android.settings/files");
+    static final File WALLPAPER_BASE_DIR = new File("/data/system/users");
     static final String WALLPAPER = "wallpaper";
-    static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER);
-
-    /**
-     * List of callbacks registered they should each be notified
-     * when the wallpaper is changed.
-     */
-    private final RemoteCallbackList<IWallpaperManagerCallback> mCallbacks
-            = new RemoteCallbackList<IWallpaperManagerCallback>();
+    static final String WALLPAPER_INFO = "wallpaper_info.xml";
 
     /**
      * Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
@@ -101,97 +97,135 @@
      * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
      * everytime the wallpaper is changed.
      */
-    private final FileObserver mWallpaperObserver = new FileObserver(
-            WALLPAPER_DIR.getAbsolutePath(), CLOSE_WRITE | DELETE | DELETE_SELF) {
-                @Override
-                public void onEvent(int event, String path) {
-                    if (path == null) {
-                        return;
-                    }
-                    synchronized (mLock) {
-                        // changing the wallpaper means we'll need to back up the new one
-                        long origId = Binder.clearCallingIdentity();
-                        BackupManager bm = new BackupManager(mContext);
-                        bm.dataChanged();
-                        Binder.restoreCallingIdentity(origId);
+    private class WallpaperObserver extends FileObserver {
 
-                        File changedFile = new File(WALLPAPER_DIR, path);
-                        if (WALLPAPER_FILE.equals(changedFile)) {
-                            notifyCallbacksLocked();
-                            if (mWallpaperComponent == null || event != CLOSE_WRITE
-                                    || mImageWallpaperPending) {
-                                if (event == CLOSE_WRITE) {
-                                    mImageWallpaperPending = false;
-                                }
-                                bindWallpaperComponentLocked(mImageWallpaperComponent,
-                                        true, false);
-                                saveSettingsLocked();
-                            }
+        final WallpaperData mWallpaper;
+        final File mWallpaperDir;
+        final File mWallpaperFile;
+
+        public WallpaperObserver(WallpaperData wallpaper) {
+            super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
+                    CLOSE_WRITE | DELETE | DELETE_SELF);
+            mWallpaperDir = getWallpaperDir(wallpaper.userId);
+            mWallpaper = wallpaper;
+            mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
+        }
+
+        @Override
+        public void onEvent(int event, String path) {
+            if (path == null) {
+                return;
+            }
+            synchronized (mLock) {
+                // changing the wallpaper means we'll need to back up the new one
+                long origId = Binder.clearCallingIdentity();
+                BackupManager bm = new BackupManager(mContext);
+                bm.dataChanged();
+                Binder.restoreCallingIdentity(origId);
+
+                File changedFile = new File(mWallpaperDir, path);
+                if (mWallpaperFile.equals(changedFile)) {
+                    notifyCallbacksLocked(mWallpaper);
+                    if (mWallpaper.wallpaperComponent == null || event != CLOSE_WRITE
+                            || mWallpaper.imageWallpaperPending) {
+                        if (event == CLOSE_WRITE) {
+                            mWallpaper.imageWallpaperPending = false;
                         }
+                        bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,
+                                false, mWallpaper);
+                        saveSettingsLocked(mWallpaper);
                     }
                 }
-            };
-    
+            }
+        }
+    }
+
     final Context mContext;
     final IWindowManager mIWindowManager;
     final MyPackageMonitor mMonitor;
+    WallpaperData mLastWallpaper;
 
-    int mWidth = -1;
-    int mHeight = -1;
+    SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
 
-    /**
-     * Client is currently writing a new image wallpaper.
-     */
-    boolean mImageWallpaperPending;
+    int mCurrentUserId;
 
-    /**
-     * Resource name if using a picture from the wallpaper gallery
-     */
-    String mName = "";
-    
-    /**
-     * The component name of the currently set live wallpaper.
-     */
-    ComponentName mWallpaperComponent;
-    
-    /**
-     * The component name of the wallpaper that should be set next.
-     */
-    ComponentName mNextWallpaperComponent;
-    
-    /**
-     * Name of the component used to display bitmap wallpapers from either the gallery or
-     * built-in wallpapers.
-     */
-    ComponentName mImageWallpaperComponent = new ComponentName("com.android.systemui",
-            "com.android.systemui.ImageWallpaper");
-    
-    WallpaperConnection mWallpaperConnection;
-    long mLastDiedTime;
-    boolean mWallpaperUpdating;
-    
+    static class WallpaperData {
+
+        int userId;
+
+        File wallpaperFile;
+
+        /**
+         * Client is currently writing a new image wallpaper.
+         */
+        boolean imageWallpaperPending;
+
+        /**
+         * Resource name if using a picture from the wallpaper gallery
+         */
+        String name = "";
+
+        /**
+         * The component name of the currently set live wallpaper.
+         */
+        ComponentName wallpaperComponent;
+
+        /**
+         * The component name of the wallpaper that should be set next.
+         */
+        ComponentName nextWallpaperComponent;
+
+        /**
+         * Name of the component used to display bitmap wallpapers from either the gallery or
+         * built-in wallpapers.
+         */
+        ComponentName imageWallpaperComponent = new ComponentName("com.android.systemui",
+                "com.android.systemui.ImageWallpaper");
+
+        WallpaperConnection connection;
+        long lastDiedTime;
+        boolean wallpaperUpdating;
+        WallpaperObserver wallpaperObserver;
+
+        /**
+         * List of callbacks registered they should each be notified when the wallpaper is changed.
+         */
+        private RemoteCallbackList<IWallpaperManagerCallback> callbacks
+                = new RemoteCallbackList<IWallpaperManagerCallback>();
+
+        int width = -1;
+        int height = -1;
+
+        WallpaperData(int userId) {
+            this.userId = userId;
+            wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+        }
+    }
+
     class WallpaperConnection extends IWallpaperConnection.Stub
             implements ServiceConnection {
         final WallpaperInfo mInfo;
         final Binder mToken = new Binder();
         IWallpaperService mService;
         IWallpaperEngine mEngine;
+        WallpaperData mWallpaper;
 
-        public WallpaperConnection(WallpaperInfo info) {
+        public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
             mInfo = info;
+            mWallpaper = wallpaper;
         }
         
         public void onServiceConnected(ComponentName name, IBinder service) {
             synchronized (mLock) {
-                if (mWallpaperConnection == this) {
-                    mLastDiedTime = SystemClock.uptimeMillis();
+                if (mWallpaper.connection == this) {
+                    mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
                     mService = IWallpaperService.Stub.asInterface(service);
-                    attachServiceLocked(this);
+                    attachServiceLocked(this, mWallpaper);
                     // XXX should probably do saveSettingsLocked() later
                     // when we have an engine, but I'm not sure about
                     // locking there and anyway we always need to be able to
                     // recover if there is something wrong.
-                    saveSettingsLocked();
+                    saveSettingsLocked(mWallpaper);
                 }
             }
         }
@@ -200,43 +234,50 @@
             synchronized (mLock) {
                 mService = null;
                 mEngine = null;
-                if (mWallpaperConnection == this) {
-                    Slog.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
-                    if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
-                                > SystemClock.uptimeMillis()) {
+                if (mWallpaper.connection == this) {
+                    Slog.w(TAG, "Wallpaper service gone: " + mWallpaper.wallpaperComponent);
+                    if (!mWallpaper.wallpaperUpdating
+                            && (mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME)
+                                > SystemClock.uptimeMillis()
+                            && mWallpaper.userId == mCurrentUserId) {
                         Slog.w(TAG, "Reverting to built-in wallpaper!");
-                        clearWallpaperLocked(true);
+                        clearWallpaperLocked(true, mWallpaper.userId);
                     }
                 }
             }
         }
-        
+
         public void attachEngine(IWallpaperEngine engine) {
             mEngine = engine;
         }
-        
+
         public ParcelFileDescriptor setWallpaper(String name) {
             synchronized (mLock) {
-                if (mWallpaperConnection == this) {
-                    return updateWallpaperBitmapLocked(name);
+                if (mWallpaper.connection == this) {
+                    return updateWallpaperBitmapLocked(name, mWallpaper);
                 }
                 return null;
             }
         }
     }
-    
+
     class MyPackageMonitor extends PackageMonitor {
         @Override
         public void onPackageUpdateFinished(String packageName, int uid) {
             synchronized (mLock) {
-                if (mWallpaperComponent != null &&
-                        mWallpaperComponent.getPackageName().equals(packageName)) {
-                    mWallpaperUpdating = false;
-                    ComponentName comp = mWallpaperComponent;
-                    clearWallpaperComponentLocked();
-                    if (!bindWallpaperComponentLocked(comp, false, false)) {
-                        Slog.w(TAG, "Wallpaper no longer available; reverting to default");
-                        clearWallpaperLocked(false);
+                for (int i = 0; i < mWallpaperMap.size(); i++) {
+                    WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+                    if (wallpaper.wallpaperComponent != null
+                            && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+                        wallpaper.wallpaperUpdating = false;
+                        ComponentName comp = wallpaper.wallpaperComponent;
+                        clearWallpaperComponentLocked(wallpaper);
+                        // Do this only for the current user's wallpaper
+                        if (wallpaper.userId == mCurrentUserId
+                                && !bindWallpaperComponentLocked(comp, false, false, wallpaper)) {
+                            Slog.w(TAG, "Wallpaper no longer available; reverting to default");
+                            clearWallpaperLocked(false, wallpaper.userId);
+                        }
                     }
                 }
             }
@@ -245,72 +286,91 @@
         @Override
         public void onPackageModified(String packageName) {
             synchronized (mLock) {
-                if (mWallpaperComponent == null ||
-                        !mWallpaperComponent.getPackageName().equals(packageName)) {
-                    return;
+                for (int i = 0; i < mWallpaperMap.size(); i++) {
+                    WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+                    if (wallpaper.wallpaperComponent == null
+                            || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+                        continue;
+                    }
+                    doPackagesChanged(true, wallpaper);
                 }
             }
-            doPackagesChanged(true);
         }
 
         @Override
         public void onPackageUpdateStarted(String packageName, int uid) {
             synchronized (mLock) {
-                if (mWallpaperComponent != null &&
-                        mWallpaperComponent.getPackageName().equals(packageName)) {
-                    mWallpaperUpdating = true;
+                for (int i = 0; i < mWallpaperMap.size(); i++) {
+                    WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+                    if (wallpaper.wallpaperComponent != null
+                            && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+                        wallpaper.wallpaperUpdating = true;
+                    }
                 }
             }
         }
 
         @Override
         public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
-            return doPackagesChanged(doit);
+            boolean changed = false;
+            for (int i = 0; i < mWallpaperMap.size(); i++) {
+                WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+                boolean res = doPackagesChanged(doit, wallpaper);
+                changed |= res;
+            }
+            return changed;
         }
 
         @Override
         public void onSomePackagesChanged() {
-            doPackagesChanged(true);
+            for (int i = 0; i < mWallpaperMap.size(); i++) {
+                WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+                doPackagesChanged(true, wallpaper);
+            }
         }
-        
-        boolean doPackagesChanged(boolean doit) {
+
+        boolean doPackagesChanged(boolean doit, WallpaperData wallpaper) {
             boolean changed = false;
             synchronized (mLock) {
-                if (mWallpaperComponent != null) {
-                    int change = isPackageDisappearing(mWallpaperComponent.getPackageName());
+                if (wallpaper.wallpaperComponent != null) {
+                    int change = isPackageDisappearing(wallpaper.wallpaperComponent
+                            .getPackageName());
                     if (change == PACKAGE_PERMANENT_CHANGE
                             || change == PACKAGE_TEMPORARY_CHANGE) {
                         changed = true;
                         if (doit) {
-                            Slog.w(TAG, "Wallpaper uninstalled, removing: " + mWallpaperComponent);
-                            clearWallpaperLocked(false);
+                            Slog.w(TAG, "Wallpaper uninstalled, removing: "
+                                    + wallpaper.wallpaperComponent);
+                            clearWallpaperLocked(false, wallpaper.userId);
                         }
                     }
                 }
-                if (mNextWallpaperComponent != null) {
-                    int change = isPackageDisappearing(mNextWallpaperComponent.getPackageName());
+                if (wallpaper.nextWallpaperComponent != null) {
+                    int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
+                            .getPackageName());
                     if (change == PACKAGE_PERMANENT_CHANGE
                             || change == PACKAGE_TEMPORARY_CHANGE) {
-                        mNextWallpaperComponent = null;
+                        wallpaper.nextWallpaperComponent = null;
                     }
                 }
-                if (mWallpaperComponent != null
-                        && isPackageModified(mWallpaperComponent.getPackageName())) {
+                if (wallpaper.wallpaperComponent != null
+                        && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
                     try {
                         mContext.getPackageManager().getServiceInfo(
-                                mWallpaperComponent, 0);
+                                wallpaper.wallpaperComponent, 0);
                     } catch (NameNotFoundException e) {
-                        Slog.w(TAG, "Wallpaper component gone, removing: " + mWallpaperComponent);
-                        clearWallpaperLocked(false);
+                        Slog.w(TAG, "Wallpaper component gone, removing: "
+                                + wallpaper.wallpaperComponent);
+                        clearWallpaperLocked(false, wallpaper.userId);
                     }
                 }
-                if (mNextWallpaperComponent != null
-                        && isPackageModified(mNextWallpaperComponent.getPackageName())) {
+                if (wallpaper.nextWallpaperComponent != null
+                        && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
                     try {
                         mContext.getPackageManager().getServiceInfo(
-                                mNextWallpaperComponent, 0);
+                                wallpaper.nextWallpaperComponent, 0);
                     } catch (NameNotFoundException e) {
-                        mNextWallpaperComponent = null;
+                        wallpaper.nextWallpaperComponent = null;
                     }
                 }
             }
@@ -325,51 +385,110 @@
                 ServiceManager.getService(Context.WINDOW_SERVICE));
         mMonitor = new MyPackageMonitor();
         mMonitor.register(context, true);
-        WALLPAPER_DIR.mkdirs();
-        loadSettingsLocked();
-        mWallpaperObserver.startWatching();
+        WALLPAPER_BASE_DIR.mkdirs();
+        loadSettingsLocked(0);
     }
     
+    private static File getWallpaperDir(int userId) {
+        return new File(WALLPAPER_BASE_DIR + "/" + userId);
+    }
+
     @Override
     protected void finalize() throws Throwable {
         super.finalize();
-        mWallpaperObserver.stopWatching();
+        for (int i = 0; i < mWallpaperMap.size(); i++) {
+            WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+            wallpaper.wallpaperObserver.stopWatching();
+        }
     }
     
     public void systemReady() {
         if (DEBUG) Slog.v(TAG, "systemReady");
+        WallpaperData wallpaper = mWallpaperMap.get(0);
+        switchWallpaper(wallpaper);
+        wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+        wallpaper.wallpaperObserver.startWatching();
+        ActivityManagerService ams = (ActivityManagerService) ServiceManager
+                .getService(Context.ACTIVITY_SERVICE);
+        ams.addUserListener(new ActivityManagerService.UserListener() {
+
+            @Override
+            public void onUserChanged(int userId) {
+                switchUser(userId);
+            }
+
+            @Override
+            public void onUserAdded(int userId) {
+            }
+
+            @Override
+            public void onUserRemoved(int userId) {
+            }
+
+            @Override
+            public void onUserLoggedOut(int userId) {
+            }
+
+        });
+    }
+
+    String getName() {
+        return mWallpaperMap.get(0).name;
+    }
+
+    void switchUser(int userId) {
+        synchronized (mLock) {
+            mCurrentUserId = userId;
+            WallpaperData wallpaper = mWallpaperMap.get(userId);
+            if (wallpaper == null) {
+                wallpaper = new WallpaperData(userId);
+                mWallpaperMap.put(userId, wallpaper);
+                loadSettingsLocked(userId);
+                wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+                wallpaper.wallpaperObserver.startWatching();
+            }
+            switchWallpaper(wallpaper);
+        }
+    }
+
+    void switchWallpaper(WallpaperData wallpaper) {
         synchronized (mLock) {
             RuntimeException e = null;
             try {
-                if (bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) {
+                ComponentName cname = wallpaper.wallpaperComponent != null ?
+                        wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
+                if (bindWallpaperComponentLocked(cname, true, false, wallpaper)) {
                     return;
                 }
             } catch (RuntimeException e1) {
                 e = e1;
             }
             Slog.w(TAG, "Failure starting previous wallpaper", e);
-            clearWallpaperLocked(false);
-        }
-    }
-    
-    public void clearWallpaper() {
-        if (DEBUG) Slog.v(TAG, "clearWallpaper");
-        synchronized (mLock) {
-            clearWallpaperLocked(false);
+            clearWallpaperLocked(false, wallpaper.userId);
         }
     }
 
-    public void clearWallpaperLocked(boolean defaultFailed) {
-        File f = WALLPAPER_FILE;
+    public void clearWallpaper() {
+        if (DEBUG) Slog.v(TAG, "clearWallpaper");
+        synchronized (mLock) {
+            clearWallpaperLocked(false, UserId.getCallingUserId());
+        }
+    }
+
+    void clearWallpaperLocked(boolean defaultFailed, int userId) {
+        WallpaperData wallpaper = mWallpaperMap.get(userId);
+        File f = new File(getWallpaperDir(userId), WALLPAPER);
         if (f.exists()) {
             f.delete();
         }
         final long ident = Binder.clearCallingIdentity();
         RuntimeException e = null;
         try {
-            mImageWallpaperPending = false;
+            wallpaper.imageWallpaperPending = false;
+            if (userId != mCurrentUserId) return;
             if (bindWallpaperComponentLocked(defaultFailed
-                    ? mImageWallpaperComponent : null, true, false)) {
+                    ? wallpaper.imageWallpaperComponent
+                    : null, true, false, wallpaper)) {
                 return;
             }
         } catch (IllegalArgumentException e1) {
@@ -383,29 +502,35 @@
         // let's not let it crash the system and just live with no
         // wallpaper.
         Slog.e(TAG, "Default wallpaper component not found!", e);
-        clearWallpaperComponentLocked();
+        clearWallpaperComponentLocked(wallpaper);
     }
 
     public void setDimensionHints(int width, int height) throws RemoteException {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
 
+        int userId = UserId.getCallingUserId();
+        WallpaperData wallpaper = mWallpaperMap.get(userId);
+        if (wallpaper == null) {
+            throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+        }
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException("width and height must be > 0");
         }
 
         synchronized (mLock) {
-            if (width != mWidth || height != mHeight) {
-                mWidth = width;
-                mHeight = height;
-                saveSettingsLocked();
-                if (mWallpaperConnection != null) {
-                    if (mWallpaperConnection.mEngine != null) {
+            if (width != wallpaper.width || height != wallpaper.height) {
+                wallpaper.width = width;
+                wallpaper.height = height;
+                saveSettingsLocked(wallpaper);
+                if (mCurrentUserId != userId) return; // Don't change the properties now
+                if (wallpaper.connection != null) {
+                    if (wallpaper.connection.mEngine != null) {
                         try {
-                            mWallpaperConnection.mEngine.setDesiredSize(
+                            wallpaper.connection.mEngine.setDesiredSize(
                                     width, height);
                         } catch (RemoteException e) {
                         }
-                        notifyCallbacksLocked();
+                        notifyCallbacksLocked(wallpaper);
                     }
                 }
             }
@@ -414,26 +539,38 @@
 
     public int getWidthHint() throws RemoteException {
         synchronized (mLock) {
-            return mWidth;
+            WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+            return wallpaper.width;
         }
     }
 
     public int getHeightHint() throws RemoteException {
         synchronized (mLock) {
-            return mHeight;
+            WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+            return wallpaper.height;
         }
     }
 
     public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
             Bundle outParams) {
         synchronized (mLock) {
+            // This returns the current user's wallpaper, if called by a system service. Else it
+            // returns the wallpaper for the calling user.
+            int callingUid = Binder.getCallingUid();
+            int wallpaperUserId = 0;
+            if (callingUid == android.os.Process.SYSTEM_UID) {
+                wallpaperUserId = mCurrentUserId;
+            } else {
+                wallpaperUserId = UserId.getUserId(callingUid);
+            }
+            WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
             try {
                 if (outParams != null) {
-                    outParams.putInt("width", mWidth);
-                    outParams.putInt("height", mHeight);
+                    outParams.putInt("width", wallpaper.width);
+                    outParams.putInt("height", wallpaper.height);
                 }
-                mCallbacks.register(cb);
-                File f = WALLPAPER_FILE;
+                wallpaper.callbacks.register(cb);
+                File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
                 if (!f.exists()) {
                     return null;
                 }
@@ -447,24 +584,30 @@
     }
 
     public WallpaperInfo getWallpaperInfo() {
+        int userId = UserId.getCallingUserId();
         synchronized (mLock) {
-            if (mWallpaperConnection != null) {
-                return mWallpaperConnection.mInfo;
+            WallpaperData wallpaper = mWallpaperMap.get(userId);
+            if (wallpaper.connection != null) {
+                return wallpaper.connection.mInfo;
             }
             return null;
         }
     }
-    
+
     public ParcelFileDescriptor setWallpaper(String name) {
         if (DEBUG) Slog.v(TAG, "setWallpaper");
-        
+        int userId = UserId.getCallingUserId();
+        WallpaperData wallpaper = mWallpaperMap.get(userId);
+        if (wallpaper == null) {
+            throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+        }
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
         synchronized (mLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+                ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
                 if (pfd != null) {
-                    mImageWallpaperPending = true;
+                    wallpaper.imageWallpaperPending = true;
                 }
                 return pfd;
             } finally {
@@ -473,19 +616,20 @@
         }
     }
 
-    ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
+    ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {
         if (name == null) name = "";
         try {
-            if (!WALLPAPER_DIR.exists()) {
-                WALLPAPER_DIR.mkdir();
+            File dir = getWallpaperDir(wallpaper.userId);
+            if (!dir.exists()) {
+                dir.mkdir();
                 FileUtils.setPermissions(
-                        WALLPAPER_DIR.getPath(),
+                        dir.getPath(),
                         FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
                         -1, -1);
             }
-            ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+            ParcelFileDescriptor fd = ParcelFileDescriptor.open(new File(dir, WALLPAPER),
                     MODE_CREATE|MODE_READ_WRITE);
-            mName = name;
+            wallpaper.name = name;
             return fd;
         } catch (FileNotFoundException e) {
             Slog.w(TAG, "Error setting wallpaper", e);
@@ -495,31 +639,36 @@
 
     public void setWallpaperComponent(ComponentName name) {
         if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
+        int userId = UserId.getCallingUserId();
+        WallpaperData wallpaper = mWallpaperMap.get(userId);
+        if (wallpaper == null) {
+            throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+        }
         checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
         synchronized (mLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                mImageWallpaperPending = false;
-                bindWallpaperComponentLocked(name, false, true);
+                wallpaper.imageWallpaperPending = false;
+                bindWallpaperComponentLocked(name, false, true, wallpaper);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
         }
     }
     
-    boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser) {
+    boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
+            boolean fromUser, WallpaperData wallpaper) {
         if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
-        
         // Has the component changed?
         if (!force) {
-            if (mWallpaperConnection != null) {
-                if (mWallpaperComponent == null) {
+            if (wallpaper.connection != null) {
+                if (wallpaper.wallpaperComponent == null) {
                     if (componentName == null) {
                         if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
                         // Still using default wallpaper.
                         return true;
                     }
-                } else if (mWallpaperComponent.equals(componentName)) {
+                } else if (wallpaper.wallpaperComponent.equals(componentName)) {
                     // Changing to same wallpaper.
                     if (DEBUG) Slog.v(TAG, "same wallpaper");
                     return true;
@@ -538,7 +687,7 @@
                 }
                 if (componentName == null) {
                     // Fall back to static image wallpaper
-                    componentName = mImageWallpaperComponent;
+                    componentName = wallpaper.imageWallpaperComponent;
                     //clearWallpaperComponentLocked();
                     //return;
                     if (DEBUG) Slog.v(TAG, "Using image wallpaper");
@@ -560,7 +709,7 @@
             WallpaperInfo wi = null;
             
             Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
-            if (componentName != null && !componentName.equals(mImageWallpaperComponent)) {
+            if (componentName != null && !componentName.equals(wallpaper.imageWallpaperComponent)) {
                 // Make sure the selected service is actually a wallpaper service.
                 List<ResolveInfo> ris = mContext.getPackageManager()
                         .queryIntentServices(intent, PackageManager.GET_META_DATA);
@@ -599,8 +748,13 @@
             
             // Bind the service!
             if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
-            WallpaperConnection newConn = new WallpaperConnection(wi);
+            WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
             intent.setComponent(componentName);
+            int serviceUserId = wallpaper.userId;
+            // Because the image wallpaper is running in the system ui
+            if (componentName.equals(wallpaper.imageWallpaperComponent)) {
+                serviceUserId = 0;
+            }
             intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
                     com.android.internal.R.string.wallpaper_binding_label);
             intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
@@ -608,8 +762,7 @@
                     Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
                             mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
                             0));
-            if (!mContext.bindService(intent, newConn,
-                    Context.BIND_AUTO_CREATE)) {
+            if (!mContext.bindService(intent, newConn, Context.BIND_AUTO_CREATE, serviceUserId)) {
                 String msg = "Unable to bind service: "
                         + componentName;
                 if (fromUser) {
@@ -618,18 +771,22 @@
                 Slog.w(TAG, msg);
                 return false;
             }
-            
-            clearWallpaperComponentLocked();
-            mWallpaperComponent = componentName;
-            mWallpaperConnection = newConn;
-            mLastDiedTime = SystemClock.uptimeMillis();
+            if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
+                detachWallpaperLocked(mLastWallpaper);
+            }
+            wallpaper.wallpaperComponent = componentName;
+            wallpaper.connection = newConn;
+            wallpaper.lastDiedTime = SystemClock.uptimeMillis();
             try {
-                if (DEBUG) Slog.v(TAG, "Adding window token: " + newConn.mToken);
-                mIWindowManager.addWindowToken(newConn.mToken,
-                        WindowManager.LayoutParams.TYPE_WALLPAPER);
+                if (wallpaper.userId == mCurrentUserId) {
+                    if (DEBUG)
+                        Slog.v(TAG, "Adding window token: " + newConn.mToken);
+                    mIWindowManager.addWindowToken(newConn.mToken,
+                            WindowManager.LayoutParams.TYPE_WALLPAPER);
+                    mLastWallpaper = wallpaper;
+                }
             } catch (RemoteException e) {
             }
-            
         } catch (PackageManager.NameNotFoundException e) {
             String msg = "Unknown component " + componentName;
             if (fromUser) {
@@ -640,54 +797,58 @@
         }
         return true;
     }
-    
-    void clearWallpaperComponentLocked() {
-        mWallpaperComponent = null;
-        if (mWallpaperConnection != null) {
-            if (mWallpaperConnection.mEngine != null) {
+
+    void detachWallpaperLocked(WallpaperData wallpaper) {
+        if (wallpaper.connection != null) {
+            if (wallpaper.connection.mEngine != null) {
                 try {
-                    mWallpaperConnection.mEngine.destroy();
+                    wallpaper.connection.mEngine.destroy();
                 } catch (RemoteException e) {
                 }
             }
-            mContext.unbindService(mWallpaperConnection);
+            mContext.unbindService(wallpaper.connection);
             try {
-                if (DEBUG) Slog.v(TAG, "Removing window token: "
-                        + mWallpaperConnection.mToken);
-                mIWindowManager.removeWindowToken(mWallpaperConnection.mToken);
+                if (DEBUG)
+                    Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
+                mIWindowManager.removeWindowToken(wallpaper.connection.mToken);
             } catch (RemoteException e) {
             }
-            mWallpaperConnection.mService = null;
-            mWallpaperConnection.mEngine = null;
-            mWallpaperConnection = null;
+            wallpaper.connection.mService = null;
+            wallpaper.connection.mEngine = null;
+            wallpaper.connection = null;
         }
     }
-    
-    void attachServiceLocked(WallpaperConnection conn) {
+
+    void clearWallpaperComponentLocked(WallpaperData wallpaper) {
+        wallpaper.wallpaperComponent = null;
+        detachWallpaperLocked(wallpaper);
+    }
+
+    void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
         try {
             conn.mService.attach(conn, conn.mToken,
                     WindowManager.LayoutParams.TYPE_WALLPAPER, false,
-                    mWidth, mHeight);
+                    wallpaper.width, wallpaper.height);
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
-            if (!mWallpaperUpdating) {
-                bindWallpaperComponentLocked(null, false, false);
+            if (!wallpaper.wallpaperUpdating) {
+                bindWallpaperComponentLocked(null, false, false, wallpaper);
             }
         }
     }
-    
-    private void notifyCallbacksLocked() {
-        final int n = mCallbacks.beginBroadcast();
+
+    private void notifyCallbacksLocked(WallpaperData wallpaper) {
+        final int n = wallpaper.callbacks.beginBroadcast();
         for (int i = 0; i < n; i++) {
             try {
-                mCallbacks.getBroadcastItem(i).onWallpaperChanged();
+                wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
             } catch (RemoteException e) {
 
                 // The RemoteCallbackList will take care of removing
                 // the dead object for us.
             }
         }
-        mCallbacks.finishBroadcast();
+        wallpaper.callbacks.finishBroadcast();
         final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
         mContext.sendBroadcast(intent);
     }
@@ -699,13 +860,13 @@
         }
     }
 
-    private static JournaledFile makeJournaledFile() {
-        final String base = "/data/system/wallpaper_info.xml";
+    private static JournaledFile makeJournaledFile(int userId) {
+        final String base = "/data/system/users/" + userId + "/" + WALLPAPER_INFO;
         return new JournaledFile(new File(base), new File(base + ".tmp"));
     }
 
-    private void saveSettingsLocked() {
-        JournaledFile journal = makeJournaledFile();
+    private void saveSettingsLocked(WallpaperData wallpaper) {
+        JournaledFile journal = makeJournaledFile(wallpaper.userId);
         FileOutputStream stream = null;
         try {
             stream = new FileOutputStream(journal.chooseForWrite(), false);
@@ -714,13 +875,13 @@
             out.startDocument(null, true);
 
             out.startTag(null, "wp");
-            out.attribute(null, "width", Integer.toString(mWidth));
-            out.attribute(null, "height", Integer.toString(mHeight));
-            out.attribute(null, "name", mName);
-            if (mWallpaperComponent != null &&
-                    !mWallpaperComponent.equals(mImageWallpaperComponent)) {
+            out.attribute(null, "width", Integer.toString(wallpaper.width));
+            out.attribute(null, "height", Integer.toString(wallpaper.height));
+            out.attribute(null, "name", wallpaper.name);
+            if (wallpaper.wallpaperComponent != null
+                    && !wallpaper.wallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
                 out.attribute(null, "component",
-                        mWallpaperComponent.flattenToShortString());
+                        wallpaper.wallpaperComponent.flattenToShortString());
             }
             out.endTag(null, "wp");
 
@@ -739,12 +900,34 @@
         }
     }
 
-    private void loadSettingsLocked() {
+    private void migrateFromOld() {
+        File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
+        File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
+        if (oldWallpaper.exists()) {
+            File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
+            oldWallpaper.renameTo(newWallpaper);
+        }
+        if (oldInfo.exists()) {
+            File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
+            oldInfo.renameTo(newInfo);
+        }
+    }
+
+    private void loadSettingsLocked(int userId) {
         if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
         
-        JournaledFile journal = makeJournaledFile();
+        JournaledFile journal = makeJournaledFile(userId);
         FileInputStream stream = null;
         File file = journal.chooseForRead();
+        if (!file.exists()) {
+            // This should only happen one time, when upgrading from a legacy system
+            migrateFromOld();
+        }
+        WallpaperData wallpaper = mWallpaperMap.get(userId);
+        if (wallpaper == null) {
+            wallpaper = new WallpaperData(userId);
+            mWallpaperMap.put(userId, wallpaper);
+        }
         boolean success = false;
         try {
             stream = new FileInputStream(file);
@@ -757,23 +940,26 @@
                 if (type == XmlPullParser.START_TAG) {
                     String tag = parser.getName();
                     if ("wp".equals(tag)) {
-                        mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
-                        mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
-                        mName = parser.getAttributeValue(null, "name");
+                        wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
+                        wallpaper.height = Integer.parseInt(parser
+                                .getAttributeValue(null, "height"));
+                        wallpaper.name = parser.getAttributeValue(null, "name");
                         String comp = parser.getAttributeValue(null, "component");
-                        mNextWallpaperComponent = comp != null
+                        wallpaper.nextWallpaperComponent = comp != null
                                 ? ComponentName.unflattenFromString(comp)
                                 : null;
-                        if (mNextWallpaperComponent == null ||
-                                "android".equals(mNextWallpaperComponent.getPackageName())) {
-                            mNextWallpaperComponent = mImageWallpaperComponent;
+                        if (wallpaper.nextWallpaperComponent == null
+                                || "android".equals(wallpaper.nextWallpaperComponent
+                                        .getPackageName())) {
+                            wallpaper.nextWallpaperComponent = wallpaper.imageWallpaperComponent;
                         }
                           
                         if (DEBUG) {
-                            Slog.v(TAG, "mWidth:" + mWidth);
-                            Slog.v(TAG, "mHeight:" + mHeight);
-                            Slog.v(TAG, "mName:" + mName);
-                            Slog.v(TAG, "mNextWallpaperComponent:" + mNextWallpaperComponent);
+                            Slog.v(TAG, "mWidth:" + wallpaper.width);
+                            Slog.v(TAG, "mHeight:" + wallpaper.height);
+                            Slog.v(TAG, "mName:" + wallpaper.name);
+                            Slog.v(TAG, "mNextWallpaperComponent:"
+                                    + wallpaper.nextWallpaperComponent);
                         }
                     }
                 }
@@ -799,70 +985,75 @@
         }
 
         if (!success) {
-            mWidth = -1;
-            mHeight = -1;
-            mName = "";
+            wallpaper.width = -1;
+            wallpaper.height = -1;
+            wallpaper.name = "";
         }
 
         // We always want to have some reasonable width hint.
         WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
         Display d = wm.getDefaultDisplay();
         int baseSize = d.getMaximumSizeDimension();
-        if (mWidth < baseSize) {
-            mWidth = baseSize;
+        if (wallpaper.width < baseSize) {
+            wallpaper.width = baseSize;
         }
-        if (mHeight < baseSize) {
-            mHeight = baseSize;
+        if (wallpaper.height < baseSize) {
+            wallpaper.height = baseSize;
         }
     }
 
     // Called by SystemBackupAgent after files are restored to disk.
     void settingsRestored() {
+        // TODO: If necessary, make it work for secondary users as well. This currently assumes
+        // restores only to the primary user
         if (DEBUG) Slog.v(TAG, "settingsRestored");
-
+        WallpaperData wallpaper = null;
         boolean success = false;
         synchronized (mLock) {
-            loadSettingsLocked();
-            if (mNextWallpaperComponent != null && 
-                    !mNextWallpaperComponent.equals(mImageWallpaperComponent)) {
-                if (!bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) {
+            loadSettingsLocked(0);
+            wallpaper = mWallpaperMap.get(0);
+            if (wallpaper.nextWallpaperComponent != null
+                    && !wallpaper.nextWallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+                if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+                        wallpaper)) {
                     // No such live wallpaper or other failure; fall back to the default
                     // live wallpaper (since the profile being restored indicated that the
                     // user had selected a live rather than static one).
-                    bindWallpaperComponentLocked(null, false, false);
+                    bindWallpaperComponentLocked(null, false, false, wallpaper);
                 }
                 success = true;
             } else {
                 // If there's a wallpaper name, we use that.  If that can't be loaded, then we
                 // use the default.
-                if ("".equals(mName)) {
+                if ("".equals(wallpaper.name)) {
                     if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
                     success = true;
                 } else {
                     if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
-                    success = restoreNamedResourceLocked();
+                    success = restoreNamedResourceLocked(wallpaper);
                 }
                 if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
                 if (success) {
-                    bindWallpaperComponentLocked(mNextWallpaperComponent, false, false);
+                    bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+                            wallpaper);
                 }
             }
         }
 
         if (!success) {
-            Slog.e(TAG, "Failed to restore wallpaper: '" + mName + "'");
-            mName = "";
-            WALLPAPER_FILE.delete();
+            Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
+            wallpaper.name = "";
+            getWallpaperDir(0).delete();
         }
 
         synchronized (mLock) {
-            saveSettingsLocked();
+            saveSettingsLocked(wallpaper);
         }
     }
 
-    boolean restoreNamedResourceLocked() {
-        if (mName.length() > 4 && "res:".equals(mName.substring(0, 4))) {
-            String resName = mName.substring(4);
+    boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
+        if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
+            String resName = wallpaper.name.substring(4);
 
             String pkg = null;
             int colon = resName.indexOf(':');
@@ -896,10 +1087,10 @@
                     }
 
                     res = r.openRawResource(resId);
-                    if (WALLPAPER_FILE.exists()) {
-                        WALLPAPER_FILE.delete();
+                    if (wallpaper.wallpaperFile.exists()) {
+                        wallpaper.wallpaperFile.delete();
                     }
-                    fos = new FileOutputStream(WALLPAPER_FILE);
+                    fos = new FileOutputStream(wallpaper.wallpaperFile);
 
                     byte[] buffer = new byte[32768];
                     int amt;
@@ -933,7 +1124,7 @@
         }
         return false;
     }
-    
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -947,20 +1138,35 @@
 
         synchronized (mLock) {
             pw.println("Current Wallpaper Service state:");
-            pw.print("  mWidth="); pw.print(mWidth);
-                    pw.print(" mHeight="); pw.println(mHeight);
-            pw.print("  mName="); pw.println(mName);
-            pw.print("  mWallpaperComponent="); pw.println(mWallpaperComponent);
-            if (mWallpaperConnection != null) {
-                WallpaperConnection conn = mWallpaperConnection;
-                pw.print("  Wallpaper connection ");
-                        pw.print(conn); pw.println(":");
-                pw.print("    mInfo.component="); pw.println(conn.mInfo.getComponent());
-                pw.print("    mToken="); pw.println(conn.mToken);
-                pw.print("    mService="); pw.println(conn.mService);
-                pw.print("    mEngine="); pw.println(conn.mEngine);
-                pw.print("    mLastDiedTime=");
-                        pw.println(mLastDiedTime - SystemClock.uptimeMillis());
+            for (int i = 0; i < mWallpaperMap.size(); i++) {
+                WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+                pw.println(" User " + wallpaper.userId + ":");
+                pw.print("  mWidth=");
+                pw.print(wallpaper.width);
+                pw.print(" mHeight=");
+                pw.println(wallpaper.height);
+                pw.print("  mName=");
+                pw.println(wallpaper.name);
+                pw.print("  mWallpaperComponent=");
+                pw.println(wallpaper.wallpaperComponent);
+                if (wallpaper.connection != null) {
+                    WallpaperConnection conn = wallpaper.connection;
+                    pw.print("  Wallpaper connection ");
+                    pw.print(conn);
+                    pw.println(":");
+                    if (conn.mInfo != null) {
+                        pw.print("    mInfo.component=");
+                        pw.println(conn.mInfo.getComponent());
+                    }
+                    pw.print("    mToken=");
+                    pw.println(conn.mToken);
+                    pw.print("    mService=");
+                    pw.println(conn.mService);
+                    pw.print("    mEngine=");
+                    pw.println(conn.mEngine);
+                    pw.print("    mLastDiedTime=");
+                    pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
+                }
             }
         }
     }
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index 6a63eac..326b940 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -191,8 +191,12 @@
         mHeadsetState = headsetState;
 
         if (headsetState == 0) {
-            Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
-            mContext.sendBroadcast(intent);
+            if (mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_sendAudioBecomingNoisy)) {
+                Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+                mContext.sendBroadcast(intent);
+            }
+
             // It can take hundreds of ms flush the audio pipeline after
             // apps pause audio playback, but audio route changes are
             // immediate, so delay the route change by 1000ms.
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 23fa94a..586a67e 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -46,7 +46,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.IWindow;
-import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -96,6 +95,10 @@
 
     private static final int DO_SET_SERVICE_INFO = 10;
 
+    public static final int ACTIVE_WINDOW_ID = -1;
+
+    public static final long ROOT_NODE_ID = -1;
+
     private static int sNextWindowId;
 
     final HandlerCaller mCaller;
@@ -140,6 +143,8 @@
 
     private final SecurityPolicy mSecurityPolicy;
 
+    private Service mUiAutomationService;
+
     /**
      * Handler for delayed event dispatch.
      */
@@ -467,7 +472,8 @@
         }
     }
 
-    public void registerEventListener(IEventListener listener) {
+    public void registerUiTestAutomationService(IEventListener listener,
+            AccessibilityServiceInfo accessibilityServiceInfo) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
                 FUNCTION_REGISTER_EVENT_LISTENER);
         ComponentName componentName = new ComponentName("foo.bar",
@@ -490,11 +496,17 @@
             }
         }
         // Hook the automation service up.
-        AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
-        accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
-        accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
-        Service service = new Service(componentName, accessibilityServiceInfo, true);
-        service.onServiceConnected(componentName, listener.asBinder());
+        mUiAutomationService = new Service(componentName, accessibilityServiceInfo, true);
+        mUiAutomationService.onServiceConnected(componentName, listener.asBinder());
+    }
+
+    public void unregisterUiTestAutomationService(IEventListener listener) {
+        synchronized (mLock) {
+            // Automation service is not bound, so pretend it died to perform clean up.
+            if (mUiAutomationService != null) {
+                mUiAutomationService.binderDied();
+            }
+        }
     }
 
     /**
@@ -727,7 +739,10 @@
      * Manages services by starting enabled ones and stopping disabled ones.
      */
     private void manageServicesLocked() {
-        unbindAutomationService();
+        // While the UI automation service is running it takes over.
+        if (mUiAutomationService != null) {
+            return;
+        }
         populateEnabledServicesLocked(mEnabledServices);
         final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices,
                 mEnabledServices);
@@ -755,21 +770,6 @@
     }
 
     /**
-     * Unbinds the automation service if such is running.
-     */
-    private void unbindAutomationService() {
-        List<Service> runningServices = mServices;
-        int runningServiceCount = mServices.size();
-        for (int i = 0; i < runningServiceCount; i++) {
-            Service service = runningServices.get(i);
-            if (service.mIsAutomation) {
-                 service.unbind();
-                 return;
-            }
-        }
-    }
-
-    /**
      * Populates a list with the {@link ComponentName}s of all enabled
      * {@link AccessibilityService}s.
      *
@@ -1070,10 +1070,11 @@
             }
         }
 
-        public float findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId,
-                int interactionId, IAccessibilityInteractionConnectionCallback callback,
-                long interrogatingTid)
+        public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
+                long accessibilityNodeId, int viewId, int interactionId,
+                IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
@@ -1081,12 +1082,8 @@
                 if (!permissionGranted) {
                     return 0;
                 } else {
-                    connection = getConnectionToRetrievalAllowingWindowLocked();
+                    connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
-                        if (DEBUG) {
-                            Slog.e(LOG_TAG, "No interaction connection to a retrieve "
-                                    + "allowing window.");
-                        }
                         return 0;
                     }
                 }
@@ -1094,44 +1091,33 @@
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.findAccessibilityNodeInfoByViewId(viewId, interactionId, callback,
-                        interrogatingPid, interrogatingTid);
+                connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId,
+                        interactionId, callback, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error finding node.");
+                    Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
             }
-            return getCompatibilityScale(mSecurityPolicy.getRetrievalAllowingWindowLocked());
+            return getCompatibilityScale(resolvedWindowId);
         }
 
-        public float findAccessibilityNodeInfosByTextInActiveWindow(
-                String text, int interactionId,
-                IAccessibilityInteractionConnectionCallback callback, long threadId)
-                throws RemoteException {
-            return findAccessibilityNodeInfosByText(text,
-                    mSecurityPolicy.mRetrievalAlowingWindowId, View.NO_ID, interactionId, callback,
-                    threadId);
-        }
-
-        public float findAccessibilityNodeInfosByText(String text,
-                int accessibilityWindowId, long accessibilityNodeId, int interactionId,
+        public float findAccessibilityNodeInfosByText(int accessibilityWindowId,
+                long accessibilityNodeId, String text, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
                 final boolean permissionGranted =
-                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
+                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
                     return 0;
                 } else {
-                    connection = getConnectionToRetrievalAllowingWindowLocked();
+                    connection = getConnectionLocked(resolvedWindowId);
                     if (connection == null) {
-                        if (DEBUG) {
-                            Slog.e(LOG_TAG, "No interaction connection to focused window.");
-                        }
                         return 0;
                     }
                 }
@@ -1139,40 +1125,35 @@
             final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                connection.findAccessibilityNodeInfosByText(text, accessibilityNodeId,
+                connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
                         interactionId, callback, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error finding node.");
+                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
             }
-            return getCompatibilityScale(accessibilityWindowId);
+            return getCompatibilityScale(resolvedWindowId);
         }
 
         public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
                 long accessibilityNodeId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
                 throws RemoteException {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
                 mSecurityPolicy.enforceCanRetrieveWindowContent(this);
                 final boolean permissionGranted =
-                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
+                    mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
                 if (!permissionGranted) {
                     return 0;
                 } else {
-                    AccessibilityConnectionWrapper wrapper =
-                        mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId);
-                    if (wrapper == null) {
-                        if (DEBUG) {
-                            Slog.e(LOG_TAG, "No interaction connection to window: "
-                                    + accessibilityWindowId);
-                        }
+                    connection = getConnectionLocked(resolvedWindowId);
+                    if (connection == null) {
                         return 0;
                     }
-                    connection = wrapper.mConnection;
                 }
             }
             final int interrogatingPid = Binder.getCallingPid();
@@ -1182,35 +1163,29 @@
                         interactionId, callback, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error requesting node with accessibilityNodeId: "
-                            + accessibilityNodeId);
+                    Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
             }
-            return getCompatibilityScale(accessibilityWindowId);
+            return getCompatibilityScale(resolvedWindowId);
         }
 
         public boolean performAccessibilityAction(int accessibilityWindowId,
                 long accessibilityNodeId, int action, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) {
+            final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
                 final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
-                        accessibilityWindowId, action);
+                        resolvedWindowId, action);
                 if (!permissionGranted) {
                     return false;
                 } else {
-                    AccessibilityConnectionWrapper wrapper =
-                        mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId);
-                    if (wrapper == null) {
-                        if (DEBUG) {
-                            Slog.e(LOG_TAG, "No interaction connection to window: "
-                                    + accessibilityWindowId);
-                        }
+                    connection = getConnectionLocked(resolvedWindowId);
+                    if (connection == null) {
                         return false;
                     }
-                    connection = wrapper.mConnection;
                 }
             }
             final int interrogatingPid = Binder.getCallingPid();
@@ -1220,8 +1195,7 @@
                         callback, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
                 if (DEBUG) {
-                    Slog.e(LOG_TAG, "Error requesting node with accessibilityNodeId: "
-                            + accessibilityNodeId);
+                    Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
                 }
             } finally {
                 Binder.restoreCallingIdentity(identityToken);
@@ -1260,19 +1234,32 @@
                 // We no longer have an automation service, so restore
                 // the state based on values in the settings database.
                 if (mIsAutomation) {
+                    mUiAutomationService = null;
                     handleAccessibilityEnabledSettingChangedLocked();
                 }
             }
         }
 
-        private IAccessibilityInteractionConnection getConnectionToRetrievalAllowingWindowLocked() {
-            final int windowId = mSecurityPolicy.getRetrievalAllowingWindowLocked();
+        private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
             }
-            AccessibilityConnectionWrapper wrapper =
-                mWindowIdToInteractionConnectionWrapperMap.get(windowId);
-            return (wrapper != null) ? wrapper.mConnection : null;
+            AccessibilityConnectionWrapper wrapper = mWindowIdToInteractionConnectionWrapperMap.get(
+                    windowId);
+            if (wrapper != null && wrapper.mConnection != null) {
+                return wrapper.mConnection;
+            }
+            if (DEBUG) {
+                Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
+            }
+            return null;
+        }
+
+        private int resolveAccessibilityWindowId(int accessibilityWindowId) {
+            if (accessibilityWindowId == ACTIVE_WINDOW_ID) {
+                return mSecurityPolicy.mRetrievalAlowingWindowId;
+            }
+            return accessibilityWindowId;
         }
 
         private float getCompatibilityScale(int windowId) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index db0a736..ac311b8 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -38,7 +38,6 @@
 import android.app.ApplicationErrorReport;
 import android.app.Dialog;
 import android.app.IActivityController;
-import android.app.IActivityWatcher;
 import android.app.IApplicationThread;
 import android.app.IInstrumentationWatcher;
 import android.app.INotificationManager;
@@ -50,6 +49,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
+import android.app.WallpaperManager;
 import android.app.backup.IBackupManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -75,6 +75,7 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -104,6 +105,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserId;
 import android.provider.Settings;
 import android.util.EventLog;
 import android.util.Pair;
@@ -111,6 +113,7 @@
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -135,6 +138,8 @@
 import java.lang.IllegalStateException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -149,7 +154,9 @@
 
 public final class ActivityManagerService extends ActivityManagerNative
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
+    private static final String USER_DATA_DIR = "/data/user/";
     static final String TAG = "ActivityManager";
+    static final String TAG_MU = "ActivityManagerServiceMU";
     static final boolean DEBUG = false;
     static final boolean localLOGV = DEBUG;
     static final boolean DEBUG_SWITCH = localLOGV || false;
@@ -158,6 +165,7 @@
     static final boolean DEBUG_OOM_ADJ = localLOGV || false;
     static final boolean DEBUG_TRANSITION = localLOGV || false;
     static final boolean DEBUG_BROADCAST = localLOGV || false;
+    static final boolean DEBUG_BACKGROUND_BROADCAST = DEBUG_BROADCAST || false;
     static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
     static final boolean DEBUG_SERVICE = localLOGV || false;
     static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false;
@@ -171,6 +179,7 @@
     static final boolean DEBUG_CONFIGURATION = localLOGV || false;
     static final boolean DEBUG_POWER = localLOGV || false;
     static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
+    static final boolean DEBUG_MU = localLOGV || false;
     static final boolean VALIDATE_TOKENS = false;
     static final boolean SHOW_ACTIVITY_START_TIME = true;
     
@@ -221,7 +230,8 @@
     static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
 
     // How long we allow a receiver to run before giving up on it.
-    static final int BROADCAST_TIMEOUT = 10*1000;
+    static final int BROADCAST_FG_TIMEOUT = 10*1000;
+    static final int BROADCAST_BG_TIMEOUT = 60*1000;
 
     // How long we wait for a service to finish executing.
     static final int SERVICE_TIMEOUT = 20*1000;
@@ -259,7 +269,14 @@
     static final String[] EMPTY_STRING_ARRAY = new String[0];
 
     public ActivityStack mMainStack;
-    
+
+    private final boolean mHeadless;
+
+    // Whether we should show our dialogs (ANR, crash, etc) or just perform their
+    // default actuion automatically.  Important for devices without direct input
+    // devices.
+    private boolean mShowDialogs = true;
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -275,34 +292,32 @@
     final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
             = new ArrayList<PendingActivityLaunch>();
     
-    /**
-     * List of all active broadcasts that are to be executed immediately
-     * (without waiting for another broadcast to finish).  Currently this only
-     * contains broadcasts to registered receivers, to avoid spinning up
-     * a bunch of processes to execute IntentReceiver components.
-     */
-    final ArrayList<BroadcastRecord> mParallelBroadcasts
-            = new ArrayList<BroadcastRecord>();
 
-    /**
-     * List of all active broadcasts that are to be executed one at a time.
-     * The object at the top of the list is the currently activity broadcasts;
-     * those after it are waiting for the top to finish..
-     */
-    final ArrayList<BroadcastRecord> mOrderedBroadcasts
-            = new ArrayList<BroadcastRecord>();
+    BroadcastQueue mFgBroadcastQueue;
+    BroadcastQueue mBgBroadcastQueue;
+    // Convenient for easy iteration over the queues. Foreground is first
+    // so that dispatch of foreground broadcasts gets precedence.
+    final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
 
-    /**
-     * Historical data of past broadcasts, for debugging.
-     */
-    static final int MAX_BROADCAST_HISTORY = 25;
-    final BroadcastRecord[] mBroadcastHistory
-            = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+    BroadcastQueue broadcastQueueForIntent(Intent intent) {
+        final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
+        if (DEBUG_BACKGROUND_BROADCAST) {
+            Slog.i(TAG, "Broadcast intent " + intent + " on "
+                    + (isFg ? "foreground" : "background")
+                    + " queue");
+        }
+        return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
+    }
 
-    /**
-     * Set when we current have a BROADCAST_INTENT_MSG in flight.
-     */
-    boolean mBroadcastsScheduled = false;
+    BroadcastRecord broadcastRecordForReceiverLocked(IBinder receiver) {
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            BroadcastRecord r = queue.getMatchingOrderedReceiver(receiver);
+            if (r != null) {
+                return r;
+            }
+        }
+        return null;
+    }
 
     /**
      * Activity we have told the window manager to have key focus.
@@ -327,6 +342,17 @@
     final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
 
     /**
+     * The currently running isolated processes.
+     */
+    final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<ProcessRecord>();
+
+    /**
+     * Counter for assigning isolated process uids, to avoid frequently reusing the
+     * same ones.
+     */
+    int mNextIsolatedProcessUid = 0;
+
+    /**
      * The currently running heavy-weight process, if any.
      */
     ProcessRecord mHeavyWeightProcess = null;
@@ -456,25 +482,6 @@
     private final StringBuilder mStrictModeBuffer = new StringBuilder();
 
     /**
-     * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
-     */
-    private boolean mPendingBroadcastTimeoutMessage;
-
-    /**
-     * Intent broadcast that we have tried to start, but are
-     * waiting for its application's process to be created.  We only
-     * need one (instead of a list) because we always process broadcasts
-     * one at a time, so no others can be started while waiting for this
-     * one.
-     */
-    BroadcastRecord mPendingBroadcast = null;
-
-    /**
-     * The receiver index that is pending, to restart the broadcast if needed.
-     */
-    int mPendingBroadcastRecvIndex;
-
-    /**
      * Keeps track of all IIntentReceivers that have been registered for
      * broadcasts.  Hash keys are the receiver IBinder, hash value is
      * a ReceiverList.
@@ -513,17 +520,7 @@
     final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
             new HashMap<String, ArrayList<Intent>>();
 
-    /**
-     * All currently running services.
-     */
-    final HashMap<ComponentName, ServiceRecord> mServices =
-        new HashMap<ComponentName, ServiceRecord>();
-
-    /**
-     * All currently running services indexed by the Intent used to start them.
-     */
-    final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
-        new HashMap<Intent.FilterComparison, ServiceRecord>();
+    final ServiceMap mServiceMap = new ServiceMap();
 
     /**
      * All currently bound service connections.  Keys are the IBinder of
@@ -571,23 +568,7 @@
      */
     final ArrayList mCancelledThumbnails = new ArrayList();
 
-    /**
-     * All of the currently running global content providers.  Keys are a
-     * string containing the provider name and values are a
-     * ContentProviderRecord object containing the data about it.  Note
-     * that a single provider may be published under multiple names, so
-     * there may be multiple entries here for a single one in mProvidersByClass.
-     */
-    final HashMap<String, ContentProviderRecord> mProvidersByName
-            = new HashMap<String, ContentProviderRecord>();
-
-    /**
-     * All of the currently running global content providers.  Keys are a
-     * string containing the provider's implementation class and values are a
-     * ContentProviderRecord object containing the data about it.
-     */
-    final HashMap<ComponentName, ContentProviderRecord> mProvidersByClass
-            = new HashMap<ComponentName, ContentProviderRecord>();
+    final ProviderMap mProviderMap = new ProviderMap();
 
     /**
      * List of content providers who have clients waiting for them.  The
@@ -619,6 +600,7 @@
             uid = _uid;
         }
     }
+
     private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
 
     /**
@@ -766,9 +748,6 @@
     int mProfileType = 0;
     boolean mAutoStopProfiler = false;
 
-    final RemoteCallbackList<IActivityWatcher> mWatchers
-            = new RemoteCallbackList<IActivityWatcher>();
-
     final RemoteCallbackList<IProcessObserver> mProcessObservers
             = new RemoteCallbackList<IProcessObserver>();
 
@@ -845,8 +824,6 @@
     static final int UPDATE_CONFIGURATION_MSG = 4;
     static final int GC_BACKGROUND_PROCESSES_MSG = 5;
     static final int WAIT_FOR_DEBUGGER_MSG = 6;
-    static final int BROADCAST_INTENT_MSG = 7;
-    static final int BROADCAST_TIMEOUT_MSG = 8;
     static final int SERVICE_TIMEOUT_MSG = 12;
     static final int UPDATE_TIME_ZONE = 13;
     static final int SHOW_UID_ERROR_MSG = 14;
@@ -866,6 +843,10 @@
     static final int DISPATCH_PROCESS_DIED = 32;
     static final int REPORT_MEM_USAGE = 33;
 
+    static final int FIRST_ACTIVITY_STACK_MSG = 100;
+    static final int FIRST_BROADCAST_QUEUE_MSG = 200;
+    static final int FIRST_COMPAT_MODE_MSG = 300;
+
     AlertDialog mUidAlert;
     CompatModeDialog mCompatModeDialog;
     long mLastMemUsageReportTime = 0;
@@ -886,7 +867,7 @@
                         return;
                     }
                     AppErrorResult res = (AppErrorResult) data.get("result");
-                    if (!mSleeping && !mShuttingDown) {
+                    if (mShowDialogs && !mSleeping && !mShuttingDown) {
                         Dialog d = new AppErrorDialog(mContext, res, proc);
                         d.show();
                         proc.crashDialog = d;
@@ -910,11 +891,12 @@
                     
                     Intent intent = new Intent("android.intent.action.ANR");
                     if (!mProcessesReady) {
-                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                                | Intent.FLAG_RECEIVER_FOREGROUND);
                     }
                     broadcastIntentLocked(null, null, intent,
                             null, null, 0, null, null, null,
-                            false, false, MY_PID, Process.SYSTEM_UID);
+                            false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
 
                     Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
                             mContext, proc, (ActivityRecord)data.get("activity"));
@@ -937,7 +919,7 @@
                         return;
                     }
                     AppErrorResult res = (AppErrorResult) data.get("result");
-                    if (!mSleeping && !mShuttingDown) {
+                    if (mShowDialogs && !mSleeping && !mShuttingDown) {
                         Dialog d = new StrictModeViolationDialog(mContext, res, proc);
                         d.show();
                         proc.crashDialog = d;
@@ -984,16 +966,6 @@
                     }
                 }
             } break;
-            case BROADCAST_INTENT_MSG: {
-                if (DEBUG_BROADCAST) Slog.v(
-                        TAG, "Received BROADCAST_INTENT_MSG");
-                processNextBroadcast(true);
-            } break;
-            case BROADCAST_TIMEOUT_MSG: {
-                synchronized (ActivityManagerService.this) {
-                    broadcastTimeoutLocked(true);
-                }
-            } break;
             case SERVICE_TIMEOUT_MSG: {
                 if (mDidDexOpt) {
                     mDidDexOpt = false;
@@ -1057,16 +1029,22 @@
                 }
             } break;
             case SHOW_UID_ERROR_MSG: {
-                // XXX This is a temporary dialog, no need to localize.
-                AlertDialog d = new BaseErrorDialog(mContext);
-                d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
-                d.setCancelable(false);
-                d.setTitle("System UIDs Inconsistent");
-                d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
-                d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky",
-                        mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
-                mUidAlert = d;
-                d.show();
+                String title = "System UIDs Inconsistent";
+                String text = "UIDs on the system are inconsistent, you need to wipe your"
+                        + " data partition or your device will be unstable.";
+                Log.e(TAG, title + ": " + text);
+                if (mShowDialogs) {
+                    // XXX This is a temporary dialog, no need to localize.
+                    AlertDialog d = new BaseErrorDialog(mContext);
+                    d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+                    d.setCancelable(false);
+                    d.setTitle(title);
+                    d.setMessage(text);
+                    d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky",
+                            mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
+                    mUidAlert = d;
+                    d.show();
+                }
             } break;
             case IM_FEELING_LUCKY_MSG: {
                 if (mUidAlert != null) {
@@ -1296,7 +1274,7 @@
         try {
             ActivityManagerService m = mSelf;
             
-            ServiceManager.addService("activity", m);
+            ServiceManager.addService("activity", m, true);
             ServiceManager.addService("meminfo", new MemBinder(m));
             ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
             ServiceManager.addService("dbinfo", new DbBinder(m));
@@ -1313,11 +1291,11 @@
             synchronized (mSelf) {
                 ProcessRecord app = mSelf.newProcessRecordLocked(
                         mSystemThread.getApplicationThread(), info,
-                        info.processName);
+                        info.processName, false);
                 app.persistent = true;
                 app.pid = MY_PID;
                 app.maxAdj = ProcessList.SYSTEM_ADJ;
-                mSelf.mProcessNames.put(app.processName, app.info.uid, app);
+                mSelf.mProcessNames.put(app.processName, app.uid, app);
                 synchronized (mSelf.mPidsSelfLocked) {
                     mSelf.mPidsSelfLocked.put(app.pid, app);
                 }
@@ -1501,6 +1479,11 @@
     private ActivityManagerService() {
         Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
         
+        mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
+        mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);
+        mBroadcastQueues[0] = mFgBroadcastQueue;
+        mBroadcastQueues[1] = mBgBroadcastQueue;
+
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
         systemDir.mkdirs();
@@ -1514,6 +1497,7 @@
         
         mUsageStatsService = new UsageStatsService(new File(
                 systemDir, "usagestats").toString());
+        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
 
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
             ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -1811,6 +1795,7 @@
                     processName);
             return procs != null ? procs.valueAt(0) : null;
         }
+        // uid = applyUserId(uid);
         ProcessRecord proc = mProcessNames.get(processName, uid);
         return proc;
     }
@@ -1834,8 +1819,15 @@
     
     final ProcessRecord startProcessLocked(String processName,
             ApplicationInfo info, boolean knownToBeDead, int intentFlags,
-            String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
-        ProcessRecord app = getProcessRecordLocked(processName, info.uid);
+            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
+            boolean isolated) {
+        ProcessRecord app;
+        if (!isolated) {
+            app = getProcessRecordLocked(processName, info.uid);
+        } else {
+            // If this is an isolated process, it can't re-use an existing process.
+            app = null;
+        }
         // We don't have to do anything more if:
         // (1) There is an existing application record; and
         // (2) The caller doesn't think it is dead, OR there is no thread
@@ -1864,36 +1856,46 @@
 
         String hostingNameStr = hostingName != null
                 ? hostingName.flattenToShortString() : null;
-        
-        if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
-            // If we are in the background, then check to see if this process
-            // is bad.  If so, we will just silently fail.
-            if (mBadProcesses.get(info.processName, info.uid) != null) {
-                if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+
+        if (!isolated) {
+            if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
+                // If we are in the background, then check to see if this process
+                // is bad.  If so, we will just silently fail.
+                if (mBadProcesses.get(info.processName, info.uid) != null) {
+                    if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+                            + "/" + info.processName);
+                    return null;
+                }
+            } else {
+                // When the user is explicitly starting a process, then clear its
+                // crash count so that we won't make it bad until they see at
+                // least one crash dialog again, and make the process good again
+                // if it had been bad.
+                if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
                         + "/" + info.processName);
-                return null;
-            }
-        } else {
-            // When the user is explicitly starting a process, then clear its
-            // crash count so that we won't make it bad until they see at
-            // least one crash dialog again, and make the process good again
-            // if it had been bad.
-            if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
-                    + "/" + info.processName);
-            mProcessCrashTimes.remove(info.processName, info.uid);
-            if (mBadProcesses.get(info.processName, info.uid) != null) {
-                EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
-                        info.processName);
-                mBadProcesses.remove(info.processName, info.uid);
-                if (app != null) {
-                    app.bad = false;
+                mProcessCrashTimes.remove(info.processName, info.uid);
+                if (mBadProcesses.get(info.processName, info.uid) != null) {
+                    EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
+                            info.processName);
+                    mBadProcesses.remove(info.processName, info.uid);
+                    if (app != null) {
+                        app.bad = false;
+                    }
                 }
             }
         }
-        
+
         if (app == null) {
-            app = newProcessRecordLocked(null, info, processName);
-            mProcessNames.put(processName, info.uid, app);
+            app = newProcessRecordLocked(null, info, processName, isolated);
+            if (app == null) {
+                Slog.w(TAG, "Failed making new process record for "
+                        + processName + "/" + info.uid + " isolated=" + isolated);
+                return null;
+            }
+            mProcessNames.put(processName, app.uid, app);
+            if (isolated) {
+                mIsolatedProcesses.put(app.uid, app);
+            }
         } else {
             // If this is a new package in the process, add the package to the list
             app.addPackage(info.packageName);
@@ -1939,13 +1941,16 @@
         mProcDeaths[0] = 0;
         
         try {
-            int uid = app.info.uid;
+            int uid = app.uid;
+
             int[] gids = null;
-            try {
-                gids = mContext.getPackageManager().getPackageGids(
-                        app.info.packageName);
-            } catch (PackageManager.NameNotFoundException e) {
-                Slog.w(TAG, "Unable to retrieve gids", e);
+            if (!app.isolated) {
+                try {
+                    gids = mContext.getPackageManager().getPackageGids(
+                            app.info.packageName);
+                } catch (PackageManager.NameNotFoundException e) {
+                    Slog.w(TAG, "Unable to retrieve gids", e);
+                }
             }
             if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
                 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
@@ -2051,7 +2056,14 @@
         }
     }
 
-    boolean startHomeActivityLocked() {
+    boolean startHomeActivityLocked(int userId) {
+        if (mHeadless) {
+            // Added because none of the other calls to ensureBootCompleted seem to fire
+            // when running headless.
+            ensureBootCompleted();
+            return false;
+        }
+
         if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
                 && mTopAction == null) {
             // We are running in factory test mode, but unable to find
@@ -2074,6 +2086,8 @@
                     aInfo.applicationInfo.packageName, aInfo.name));
             // Don't do this if the home app is currently being
             // instrumented.
+            aInfo = new ActivityInfo(aInfo);
+            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
             ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                     aInfo.applicationInfo.uid);
             if (app == null || app.instrumentationClass == null) {
@@ -2082,11 +2096,10 @@
                         null, null, 0, 0, 0, false, false, null);
             }
         }
-        
-        
+
         return true;
     }
-    
+
     /**
      * Starts the "new version setup screen" if appropriate.
      */
@@ -2145,37 +2158,52 @@
         return mCompatModePackages.compatibilityInfoForPackageLocked(ai);
     }
 
+    void enforceNotIsolatedCaller(String caller) {
+        if (UserId.isIsolated(Binder.getCallingUid())) {
+            throw new SecurityException("Isolated process not allowed to call " + caller);
+        }
+    }
+
     public int getFrontActivityScreenCompatMode() {
+        enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
         synchronized (this) {
             return mCompatModePackages.getFrontActivityScreenCompatModeLocked();
         }
     }
 
     public void setFrontActivityScreenCompatMode(int mode) {
+        enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+                "setFrontActivityScreenCompatMode");
         synchronized (this) {
             mCompatModePackages.setFrontActivityScreenCompatModeLocked(mode);
         }
     }
 
     public int getPackageScreenCompatMode(String packageName) {
+        enforceNotIsolatedCaller("getPackageScreenCompatMode");
         synchronized (this) {
             return mCompatModePackages.getPackageScreenCompatModeLocked(packageName);
         }
     }
 
     public void setPackageScreenCompatMode(String packageName, int mode) {
+        enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+                "setPackageScreenCompatMode");
         synchronized (this) {
             mCompatModePackages.setPackageScreenCompatModeLocked(packageName, mode);
         }
     }
 
     public boolean getPackageAskScreenCompat(String packageName) {
+        enforceNotIsolatedCaller("getPackageAskScreenCompat");
         synchronized (this) {
             return mCompatModePackages.getPackageAskCompatModeLocked(packageName);
         }
     }
 
     public void setPackageAskScreenCompat(String packageName, boolean ask) {
+        enforceCallingPermission(android.Manifest.permission.SET_SCREEN_COMPATIBILITY,
+                "setPackageAskScreenCompat");
         synchronized (this) {
             mCompatModePackages.setPackageAskCompatModeLocked(packageName, ask);
         }
@@ -2186,19 +2214,6 @@
         
         final int identHash = System.identityHashCode(r);
         updateUsageStats(r, true);
-        
-        int i = mWatchers.beginBroadcast();
-        while (i > 0) {
-            i--;
-            IActivityWatcher w = mWatchers.getBroadcastItem(i);
-            if (w != null) {
-                try {
-                    w.activityResuming(identHash);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-        mWatchers.finishBroadcast();
     }
 
     private void dispatchForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
@@ -2250,10 +2265,24 @@
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
             String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+        enforceNotIsolatedCaller("startActivity");
+        int userId = 0;
+        if (intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
+            // Requesting home, set the identity to the current user
+            // HACK!
+            userId = mCurrentUserId;
+        } else {
+            // TODO: Fix this in a better way - calls coming from SystemUI should probably carry
+            // the current user's userId
+            if (Binder.getCallingUid() < Process.FIRST_APPLICATION_UID) {
+                userId = 0;
+            } else {
+                userId = Binder.getOrigCallingUser();
+            }
+        }
         return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
-                grantedUriPermissions, grantedMode, resultTo, resultWho,
-                requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler,
-                null, null);
+                grantedUriPermissions, grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded,
+                debug, profileFile, profileFd, autoStopProfiler, null, null, userId);
     }
 
     public final WaitResult startActivityAndWait(IApplicationThread caller,
@@ -2261,11 +2290,13 @@
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
             String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+        enforceNotIsolatedCaller("startActivityAndWait");
         WaitResult res = new WaitResult();
+        int userId = Binder.getOrigCallingUser();
         mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
                 grantedUriPermissions, grantedMode, resultTo, resultWho,
                 requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler,
-                res, null);
+                res, null, userId);
         return res;
     }
     
@@ -2274,15 +2305,19 @@
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded,
             boolean debug, Configuration config) {
-        return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
+        enforceNotIsolatedCaller("startActivityWithConfig");
+        int ret = mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
                 grantedUriPermissions, grantedMode, resultTo, resultWho,
-                requestCode, onlyIfNeeded, debug, null, null, false, null, config);
+                requestCode, onlyIfNeeded,
+                debug, null, null, false, null, config, Binder.getOrigCallingUser());
+        return ret;
     }
 
     public int startActivityIntentSender(IApplicationThread caller,
             IntentSender intent, Intent fillInIntent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode,
             int flagsMask, int flagsValues) {
+        enforceNotIsolatedCaller("startActivityIntentSender");
         // Refuse possible leaked file descriptors
         if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -2304,9 +2339,9 @@
                 mAppSwitchesAllowedTime = 0;
             }
         }
-        
-        return pir.sendInner(0, fillInIntent, resolvedType, null,
+        int ret = pir.sendInner(0, fillInIntent, resolvedType, null,
                 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
+        return ret;
     }
     
     public boolean startNextMatchingActivity(IBinder callingActivity,
@@ -2409,20 +2444,25 @@
         
         // This is so super not safe, that only the system (or okay root)
         // can do it.
+        int userId = Binder.getOrigCallingUser();
         final int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != Process.myUid()) {
             throw new SecurityException(
                     "startActivityInPackage only available to the system");
         }
 
-        return mMainStack.startActivityMayWait(null, uid, intent, resolvedType,
+        int ret = mMainStack.startActivityMayWait(null, uid, intent, resolvedType,
                 null, 0, resultTo, resultWho, requestCode, onlyIfNeeded, false,
-                null, null, false, null, null);
+                null, null, false, null, null, userId);
+        return ret;
     }
 
     public final int startActivities(IApplicationThread caller,
             Intent[] intents, String[] resolvedTypes, IBinder resultTo) {
-        return mMainStack.startActivities(caller, -1, intents, resolvedTypes, resultTo);
+        enforceNotIsolatedCaller("startActivities");
+        int ret = mMainStack.startActivities(caller, -1, intents, resolvedTypes, resultTo,
+                Binder.getOrigCallingUser());
+        return ret;
     }
 
     public final int startActivitiesInPackage(int uid,
@@ -2435,8 +2475,9 @@
             throw new SecurityException(
                     "startActivityInPackage only available to the system");
         }
-
-        return mMainStack.startActivities(null, uid, intents, resolvedTypes, resultTo);
+        int ret = mMainStack.startActivities(null, uid, intents, resolvedTypes, resultTo,
+                UserId.getUserId(uid));
+        return ret;
     }
 
     final void addRecentTaskLocked(TaskRecord task) {
@@ -2448,8 +2489,9 @@
         // Remove any existing entries that are the same kind of task.
         for (int i=0; i<N; i++) {
             TaskRecord tr = mRecentTasks.get(i);
-            if ((task.affinity != null && task.affinity.equals(tr.affinity))
-                    || (task.intent != null && task.intent.filterEquals(tr.intent))) {
+            if (task.userId == tr.userId
+                    && ((task.affinity != null && task.affinity.equals(tr.affinity))
+                    || (task.intent != null && task.intent.filterEquals(tr.intent)))) {
                 mRecentTasks.remove(i);
                 i--;
                 N--;
@@ -2594,7 +2636,7 @@
             synchronized (mPidsSelfLocked) {
                 for (int i=0; i<mPidsSelfLocked.size(); i++) {
                     ProcessRecord p = mPidsSelfLocked.valueAt(i);
-                    if (p.info.uid != uid) {
+                    if (p.uid != uid) {
                         continue;
                     }
                     if (p.pid == initialPid) {
@@ -2710,13 +2752,7 @@
         }
 
         // Just in case...
-        if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) {
-            if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity);
-            mMainStack.mPausingActivity = null;
-        }
-        if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) {
-            mMainStack.mLastPausedActivity = null;
-        }
+        mMainStack.appDiedLocked(app);
 
         // Remove this application's activities from active lists.
         mMainStack.removeHistoryRecordsForAppLocked(app);
@@ -2808,7 +2844,6 @@
 
     private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
         IBinder threadBinder = thread.asBinder();
-
         // Find the application record.
         for (int i=mLruProcesses.size()-1; i>=0; i--) {
             ProcessRecord rec = mLruProcesses.get(i);
@@ -2994,21 +3029,6 @@
         }
     }
 
-    private final class AppNotResponding implements Runnable {
-        private final ProcessRecord mApp;
-        private final String mAnnotation;
-
-        public AppNotResponding(ProcessRecord app, String annotation) {
-            mApp = app;
-            mAnnotation = annotation;
-        }
-
-        @Override
-        public void run() {
-            appNotResponding(mApp, null, null, mAnnotation);
-        }
-    }
-
     final void appNotResponding(ProcessRecord app, ActivityRecord activity,
             ActivityRecord parent, final String annotation) {
         ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
@@ -3185,7 +3205,8 @@
     }
     
     public boolean clearApplicationUserData(final String packageName,
-            final IPackageDataObserver observer) {
+            final IPackageDataObserver observer, final int userId) {
+        enforceNotIsolatedCaller("clearApplicationUserData");
         int uid = Binder.getCallingUid();
         int pid = Binder.getCallingPid();
         long callingId = Binder.clearCallingIdentity();
@@ -3220,7 +3241,7 @@
                         Uri.fromParts("package", packageName, null));
                 intent.putExtra(Intent.EXTRA_UID, pkgUid);
                 broadcastIntentInPackage("android", Process.SYSTEM_UID, intent,
-                        null, null, 0, null, null, null, false, false);
+                        null, null, 0, null, null, null, false, false, userId);
             } catch (RemoteException e) {
             }
         } finally {
@@ -3315,7 +3336,7 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        
+        final int userId = Binder.getOrigCallingUser();
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -3323,6 +3344,8 @@
             synchronized(this) {
                 try {
                     pkgUid = pm.getPackageUid(packageName);
+                    // Convert the uid to the one for the calling user
+                    pkgUid = UserId.getUid(userId, pkgUid);
                 } catch (RemoteException e) {
                 }
                 if (pkgUid == -1) {
@@ -3372,6 +3395,7 @@
     }
 
     public void closeSystemDialogs(String reason) {
+        enforceNotIsolatedCaller("closeSystemDialogs");
         Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         if (reason != null) {
@@ -3381,22 +3405,9 @@
         final int uid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         synchronized (this) {
-            int i = mWatchers.beginBroadcast();
-            while (i > 0) {
-                i--;
-                IActivityWatcher w = mWatchers.getBroadcastItem(i);
-                if (w != null) {
-                    try {
-                        w.closingSystemDialogs(reason);
-                    } catch (RemoteException e) {
-                    }
-                }
-            }
-            mWatchers.finishBroadcast();
-            
             mWindowManager.closeSystemDialogs(reason);
             
-            for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
+            for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
                 ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
                 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
                     r.stack.finishActivityLocked(r, i,
@@ -3405,13 +3416,14 @@
             }
             
             broadcastIntentLocked(null, null, intent, null,
-                    null, 0, null, null, null, false, false, -1, uid);
+                    null, 0, null, null, null, false, false, -1, uid, 0 /* TODO: Verify */);
         }
         Binder.restoreCallingIdentity(origId);
     }
     
     public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
             throws RemoteException {
+        enforceNotIsolatedCaller("getProcessMemoryInfo");
         Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
         for (int i=pids.length-1; i>=0; i--) {
             infos[i] = new Debug.MemoryInfo();
@@ -3421,6 +3433,7 @@
     }
 
     public long[] getProcessPss(int[] pids) throws RemoteException {
+        enforceNotIsolatedCaller("getProcessPss");
         long[] pss = new long[pids.length];
         for (int i=pids.length-1; i>=0; i--) {
             pss[i] = Debug.getPss(pids[i]);
@@ -3465,7 +3478,8 @@
         intent.putExtra(Intent.EXTRA_UID, uid);
         broadcastIntentLocked(null, null, intent,
                 null, null, 0, null, null, null,
-                false, false, MY_PID, Process.SYSTEM_UID);
+                false, false,
+                MY_PID, Process.SYSTEM_UID, UserId.getUserId(uid));
     }
     
     private final boolean killPackageProcessesLocked(String packageName, int uid,
@@ -3569,7 +3583,8 @@
         }
 
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
-        for (ServiceRecord service : mServices.values()) {
+        int userId = UserId.getUserId(uid);
+        for (ServiceRecord service : mServiceMap.getAllServices(userId)) {
             if (service.packageName.equals(name)
                     && (service.app == null || evenPersistent || !service.app.persistent)) {
                 if (!doit) {
@@ -3581,6 +3596,7 @@
                     service.app.removed = true;
                 }
                 service.app = null;
+                service.isolatedProc = null;
                 services.add(service);
             }
         }
@@ -3591,7 +3607,7 @@
         }
 
         ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
-        for (ContentProviderRecord provider : mProvidersByClass.values()) {
+        for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) {
             if (provider.info.packageName.equals(name)
                     && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
                 if (!doit) {
@@ -3626,12 +3642,13 @@
     private final boolean removeProcessLocked(ProcessRecord app,
             boolean callerWillRestart, boolean allowRestart, String reason) {
         final String name = app.processName;
-        final int uid = app.info.uid;
+        final int uid = app.uid;
         if (DEBUG_PROCESSES) Slog.d(
             TAG, "Force removing proc " + app.toShortString() + " (" + name
             + "/" + uid + ")");
 
         mProcessNames.remove(name, uid);
+        mIsolatedProcesses.remove(app.uid);
         if (mHeavyWeightProcess == app) {
             mHeavyWeightProcess = null;
             mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
@@ -3648,9 +3665,9 @@
             mLruProcesses.remove(app);
             Process.killProcessQuiet(pid);
             
-            if (app.persistent) {
+            if (app.persistent && !app.isolated) {
                 if (!callerWillRestart) {
-                    addAppLocked(app.info);
+                    addAppLocked(app.info, false);
                 } else {
                     needRestart = true;
                 }
@@ -3675,9 +3692,10 @@
         
         if (gone) {
             Slog.w(TAG, "Process " + app + " failed to attach");
-            EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
+            EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.uid,
                     app.processName);
-            mProcessNames.remove(app.processName, app.info.uid);
+            mProcessNames.remove(app.processName, app.uid);
+            mIsolatedProcesses.remove(app.uid);
             if (mHeavyWeightProcess == app) {
                 mHeavyWeightProcess = null;
                 mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
@@ -3687,9 +3705,11 @@
             // Take care of any services that are waiting for the process.
             for (int i=0; i<mPendingServices.size(); i++) {
                 ServiceRecord sr = mPendingServices.get(i);
-                if (app.info.uid == sr.appInfo.uid
-                        && app.processName.equals(sr.processName)) {
+                if ((app.uid == sr.appInfo.uid
+                        && app.processName.equals(sr.processName))
+                        || sr.isolatedProc == app) {
                     Slog.w(TAG, "Forcing bringing down service: " + sr);
+                    sr.isolatedProc = null;
                     mPendingServices.remove(i);
                     i--;
                     bringDownServiceLocked(sr, true);
@@ -3708,12 +3728,9 @@
                     // Can't happen; the backup manager is local
                 }
             }
-            if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
+            if (isPendingBroadcastProcessLocked(pid)) {
                 Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
-                mPendingBroadcast.state = BroadcastRecord.IDLE;
-                mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
-                mPendingBroadcast = null;
-                scheduleBroadcastsLocked();
+                skipPendingBroadcastLocked(pid);
             }
         } else {
             Slog.w(TAG, "Spurious process start timeout - pid not known for " + app);
@@ -3873,10 +3890,12 @@
         // See if the top visible activity is waiting to run in this process...
         ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
         if (hr != null && normalMode) {
-            if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
+            if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                     && processName.equals(hr.processName)) {
                 try {
-                    if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
+                    if (mHeadless) {
+                        Slog.e(TAG, "Starting activities not supported on headless device: " + hr);
+                    } else if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
                         didSomething = true;
                     }
                 } catch (Exception e) {
@@ -3895,8 +3914,8 @@
             try {
                 for (int i=0; i<mPendingServices.size(); i++) {
                     sr = mPendingServices.get(i);
-                    if (app.info.uid != sr.appInfo.uid
-                            || !processName.equals(sr.processName)) {
+                    if (app != sr.isolatedProc && (app.uid != sr.appInfo.uid
+                            || !processName.equals(sr.processName))) {
                         continue;
                     }
 
@@ -3912,28 +3931,18 @@
             }
         }
 
-        // Check if the next broadcast receiver is in this process...
-        BroadcastRecord br = mPendingBroadcast;
-        if (!badApp && br != null && br.curApp == app) {
+        // Check if a next-broadcast receiver is in this process...
+        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
             try {
-                mPendingBroadcast = null;
-                processCurBroadcastLocked(br, app);
-                didSomething = true;
+                didSomething = sendPendingBroadcastsLocked(app);
             } catch (Exception e) {
-                Slog.w(TAG, "Exception in new application when starting receiver "
-                      + br.curComponent.flattenToShortString(), e);
+                // If the app died trying to launch the receiver we declare it 'bad'
                 badApp = true;
-                logBroadcastReceiverDiscardLocked(br);
-                finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
-                        br.resultExtras, br.resultAbort, true);
-                scheduleBroadcastsLocked();
-                // We need to reset the state if we fails to start the receiver.
-                br.state = BroadcastRecord.IDLE;
             }
         }
 
         // Check whether the next backup agent is in this process...
-        if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
+        if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
             if (DEBUG_BACKUP) Slog.v(TAG, "New app is backup target, launching agent for " + app);
             ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
             try {
@@ -3995,10 +4004,12 @@
     }
 
     public void showBootMessage(final CharSequence msg, final boolean always) {
+        enforceNotIsolatedCaller("showBootMessage");
         mWindowManager.showBootMessage(msg, always);
     }
 
     public void dismissKeyguardOnNextActivity() {
+        enforceNotIsolatedCaller("dismissKeyguardOnNextActivity");
         synchronized (this) {
             mMainStack.dismissKeyguardOnNextActivityLocked();
         }
@@ -4046,11 +4057,12 @@
                 // Tell anyone interested that we are done booting!
                 SystemProperties.set("sys.boot_completed", "1");
                 SystemProperties.set("dev.bootcomplete", "1");
+                /* TODO: Send this to all users that are to be logged in on startup */
                 broadcastIntentLocked(null, null,
                         new Intent(Intent.ACTION_BOOT_COMPLETED, null),
                         null, null, 0, null, null,
                         android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
-                        false, false, MY_PID, Process.SYSTEM_UID);
+                        false, false, MY_PID, Process.SYSTEM_UID, Binder.getOrigCallingUser());
             }
         }
     }
@@ -4160,6 +4172,7 @@
     public IIntentSender getIntentSender(int type,
             String packageName, IBinder token, String resultWho,
             int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
+        enforceNotIsolatedCaller("getIntentSender");
         // Refuse possible leaked file descriptors
         if (intents != null) {
             if (intents.length < 1) {
@@ -4191,7 +4204,7 @@
                 if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
                     int uid = AppGlobals.getPackageManager()
                             .getPackageUid(packageName);
-                    if (uid != Binder.getCallingUid()) {
+                    if (UserId.getAppId(callingUid) != uid) {
                         String msg = "Permission Denial: getIntentSender() from pid="
                             + Binder.getCallingPid()
                             + ", uid=" + Binder.getCallingUid()
@@ -4202,7 +4215,10 @@
                     }
                 }
                 
-                return getIntentSenderLocked(type, packageName, callingUid,
+                if (DEBUG_MU)
+                    Slog.i(TAG_MU, "Getting intent sender for origCallingUid="
+                            + Binder.getOrigCallingUid());
+                return getIntentSenderLocked(type, packageName, Binder.getOrigCallingUid(),
                         token, resultWho, requestCode, intents, resolvedTypes, flags);
                 
             } catch (RemoteException e) {
@@ -4214,6 +4230,8 @@
     IIntentSender getIntentSenderLocked(int type,
             String packageName, int callingUid, IBinder token, String resultWho,
             int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
+        if (DEBUG_MU)
+            Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
         ActivityRecord activity = null;
         if (type == INTENT_SENDER_ACTIVITY_RESULT) {
             activity = mMainStack.isInStackLocked(token);
@@ -4382,7 +4400,7 @@
             
             synchronized (mPidsSelfLocked) {
                 ProcessRecord pr = mPidsSelfLocked.get(pid);
-                if (pr == null) {
+                if (pr == null && isForeground) {
                     Slog.w(TAG, "setProcessForeground called on unknown pid: " + pid);
                     return;
                 }
@@ -4390,7 +4408,9 @@
                 if (oldToken != null) {
                     oldToken.token.unlinkToDeath(oldToken, 0);
                     mForegroundProcesses.remove(pid);
-                    pr.forcingToForeground = null;
+                    if (pr != null) {
+                        pr.forcingToForeground = null;
+                    }
                     changed = true;
                 }
                 if (isForeground && token != null) {
@@ -4455,9 +4475,13 @@
         if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID) {
             return PackageManager.PERMISSION_GRANTED;
         }
+        // Isolated processes don't get any permissions.
+        if (UserId.isIsolated(uid)) {
+            return PackageManager.PERMISSION_DENIED;
+        }
         // If there is a uid that owns whatever is being accessed, it has
         // blanket access to it regardless of the permissions it requires.
-        if (owningUid >= 0 && uid == owningUid) {
+        if (owningUid >= 0 && UserId.isSameApp(uid, owningUid)) {
             return PackageManager.PERMISSION_GRANTED;
         }
         // If the target is not exported, then nobody else can get to it.
@@ -4491,7 +4515,7 @@
         if (permission == null) {
             return PackageManager.PERMISSION_DENIED;
         }
-        return checkComponentPermission(permission, pid, uid, -1, true);
+        return checkComponentPermission(permission, pid, UserId.getAppId(uid), -1, true);
     }
 
     /**
@@ -4501,7 +4525,7 @@
     int checkCallingPermission(String permission) {
         return checkPermission(permission,
                 Binder.getCallingPid(),
-                Binder.getCallingUid());
+                UserId.getAppId(Binder.getCallingUid()));
     }
 
     /**
@@ -4607,6 +4631,8 @@
     }
 
     public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
+        enforceNotIsolatedCaller("checkUriPermission");
+
         // Another redirected-binder-call permissions check as in
         // {@link checkComponentPermission}.
         Identity tlsIdentity = sCallerIdentity.get();
@@ -4615,6 +4641,7 @@
             pid = tlsIdentity.pid;
         }
 
+        uid = UserId.getAppId(uid);
         // Our own process gets to do everything.
         if (pid == MY_PID) {
             return PackageManager.PERMISSION_GRANTED;
@@ -4657,7 +4684,8 @@
 
         String name = uri.getAuthority();
         ProviderInfo pi = null;
-        ContentProviderRecord cpr = mProvidersByName.get(name);
+        ContentProviderRecord cpr = mProviderMap.getProviderByName(name,
+                UserId.getUserId(callingUid));
         if (cpr != null) {
             pi = cpr.info;
         } else {
@@ -4755,6 +4783,7 @@
 
     public int checkGrantUriPermission(int callingUid, String targetPkg,
             Uri uri, int modeFlags) {
+        enforceNotIsolatedCaller("checkGrantUriPermission");
         synchronized(this) {
             return checkGrantUriPermissionLocked(callingUid, targetPkg, uri, modeFlags);
         }
@@ -4863,6 +4892,7 @@
 
     public void grantUriPermission(IApplicationThread caller, String targetPkg,
             Uri uri, int modeFlags) {
+        enforceNotIsolatedCaller("grantUriPermission");
         synchronized(this) {
             final ProcessRecord r = getRecordForAppLocked(caller);
             if (r == null) {
@@ -4877,7 +4907,7 @@
                 throw new IllegalArgumentException("null uri");
             }
 
-            grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
+            grantUriPermissionLocked(r.uid, targetPkg, uri, modeFlags,
                     null);
         }
     }
@@ -4913,7 +4943,8 @@
 
         final String authority = uri.getAuthority();
         ProviderInfo pi = null;
-        ContentProviderRecord cpr = mProvidersByName.get(authority);
+        ContentProviderRecord cpr = mProviderMap.getProviderByName(authority,
+                UserId.getUserId(callingUid));
         if (cpr != null) {
             pi = cpr.info;
         } else {
@@ -4985,6 +5016,7 @@
 
     public void revokeUriPermission(IApplicationThread caller, Uri uri,
             int modeFlags) {
+        enforceNotIsolatedCaller("revokeUriPermission");
         synchronized(this) {
             final ProcessRecord r = getRecordForAppLocked(caller);
             if (r == null) {
@@ -5007,7 +5039,7 @@
 
             final String authority = uri.getAuthority();
             ProviderInfo pi = null;
-            ContentProviderRecord cpr = mProvidersByName.get(authority);
+            ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, r.userId);
             if (cpr != null) {
                 pi = cpr.info;
             } else {
@@ -5023,12 +5055,13 @@
                 return;
             }
 
-            revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
+            revokeUriPermissionLocked(r.uid, uri, modeFlags);
         }
     }
 
     @Override
     public IBinder newUriPermissionOwner(String name) {
+        enforceNotIsolatedCaller("newUriPermissionOwner");
         synchronized(this) {
             UriPermissionOwner owner = new UriPermissionOwner(this, name);
             return owner.getExternalTokenLocked();
@@ -5246,6 +5279,12 @@
 
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
             int flags) {
+        final int callingUid = Binder.getCallingUid();
+        // If it's the system uid asking, then use the current user id.
+        // TODO: Make sure that there aren't any other legitimate calls from the system uid that
+        // require the entire list.
+        final int callingUserId = callingUid == Process.SYSTEM_UID
+                ? mCurrentUserId : UserId.getUserId(callingUid);
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.GET_TASKS,
                     "getRecentTasks()");
@@ -5258,11 +5297,14 @@
                             maxNum < N ? maxNum : N);
             for (int i=0; i<N && maxNum > 0; i++) {
                 TaskRecord tr = mRecentTasks.get(i);
+                // Only add calling user's recent tasks
+                if (tr.userId != callingUserId) continue;
                 // Return the entry if desired by the caller.  We always return
                 // the first entry, because callers always expect this to be the
-                // forground app.  We may filter others if the caller has
+                // foreground app.  We may filter others if the caller has
                 // not supplied RECENT_WITH_EXCLUDED and there is some reason
                 // we should exclude the entry.
+
                 if (i == 0
                         || ((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
                         || (tr.intent == null)
@@ -5351,7 +5393,7 @@
 
         // Find any running services associated with this app.
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
-        for (ServiceRecord sr : mServices.values()) {
+        for (ServiceRecord sr : mServiceMap.getAllServices(root.userId)) {
             if (sr.packageName.equals(component.getPackageName())) {
                 services.add(sr);
             }
@@ -5556,6 +5598,7 @@
      * @return Returns true if the move completed, false if not.
      */
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
+        enforceNotIsolatedCaller("moveActivityTaskToBack");
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
             int taskId = getTaskForActivityLocked(token, !nonRoot);
@@ -5609,29 +5652,6 @@
         return -1;
     }
 
-    public void finishOtherInstances(IBinder token, ComponentName className) {
-        synchronized(this) {
-            final long origId = Binder.clearCallingIdentity();
-
-            int N = mMainStack.mHistory.size();
-            TaskRecord lastTask = null;
-            for (int i=0; i<N; i++) {
-                ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
-                if (r.realActivity.equals(className)
-                        && r.appToken != token && lastTask != r.task) {
-                    if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                            null, "others")) {
-                        i--;
-                        N--;
-                    }
-                }
-                lastTask = r.task;
-            }
-
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
     // =========================================================
     // THUMBNAILS
     // =========================================================
@@ -5718,21 +5738,27 @@
         List<ProviderInfo> providers = null;
         try {
             providers = AppGlobals.getPackageManager().
-                queryContentProviders(app.processName, app.info.uid,
+                queryContentProviders(app.processName, app.uid,
                         STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
         } catch (RemoteException ex) {
         }
+        if (DEBUG_MU)
+            Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
+        int userId = app.userId;
         if (providers != null) {
             final int N = providers.size();
             for (int i=0; i<N; i++) {
                 ProviderInfo cpi =
                     (ProviderInfo)providers.get(i);
+
                 ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
-                ContentProviderRecord cpr = mProvidersByClass.get(comp);
+                ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
                 if (cpr == null) {
                     cpr = new ContentProviderRecord(cpi, app.info, comp);
-                    mProvidersByClass.put(comp, cpr);
+                    mProviderMap.putProviderByClass(comp, cpr);
                 }
+                if (DEBUG_MU)
+                    Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
                 app.pubProviders.put(cpi.name, cpr);
                 app.addPackage(cpi.applicationInfo.packageName);
                 ensurePackageDexOpt(cpi.applicationInfo.packageName);
@@ -5744,7 +5770,7 @@
     private final String checkContentProviderPermissionLocked(
             ProviderInfo cpi, ProcessRecord r) {
         final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
-        final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
+        final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
         if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
                 cpi.applicationInfo.uid, cpi.exported)
                 == PackageManager.PERMISSION_GRANTED) {
@@ -5842,8 +5868,8 @@
         return false;
     }
 
-    private final ContentProviderHolder getContentProviderImpl(
-        IApplicationThread caller, String name) {
+    private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
+            String name) {
         ContentProviderRecord cpr;
         ProviderInfo cpi = null;
 
@@ -5860,7 +5886,8 @@
             }
 
             // First check if this content provider has been published...
-            cpr = mProvidersByName.get(name);
+            int userId = UserId.getUserId(r != null ? r.uid : Binder.getCallingUid());
+            cpr = mProviderMap.getProviderByName(name, userId);
             boolean providerRunning = cpr != null;
             if (providerRunning) {
                 cpi = cpr.info;
@@ -5945,6 +5972,9 @@
                     return null;
                 }
 
+                cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo,
+                        Binder.getOrigCallingUser());
+
                 String msg;
                 if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) {
                     throw new SecurityException(msg);
@@ -5960,7 +5990,7 @@
                 }
 
                 ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
-                cpr = mProvidersByClass.get(comp);
+                cpr = mProviderMap.getProviderByClass(comp, Binder.getOrigCallingUser());
                 final boolean firstClass = cpr == null;
                 if (firstClass) {
                     try {
@@ -5974,6 +6004,7 @@
                                     + cpi.name);
                             return null;
                         }
+                        ai = getAppInfoForUser(ai, Binder.getOrigCallingUser());
                         cpr = new ContentProviderRecord(cpi, ai, comp);
                     } catch (RemoteException ex) {
                         // pm is in same process, this will never happen.
@@ -5990,7 +6021,7 @@
 
                 if (DEBUG_PROVIDER) {
                     RuntimeException e = new RuntimeException("here");
-                    Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
+                    Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.uid
                           + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
                 }
 
@@ -6024,7 +6055,7 @@
                         ProcessRecord proc = startProcessLocked(cpi.processName,
                                 cpr.appInfo, false, 0, "content provider",
                                 new ComponentName(cpi.applicationInfo.packageName,
-                                        cpi.name), false);
+                                        cpi.name), false, false);
                         if (proc == null) {
                             Slog.w(TAG, "Unable to launch app "
                                     + cpi.applicationInfo.packageName + "/"
@@ -6042,9 +6073,9 @@
                 // Make sure the provider is published (the same provider class
                 // may be published under multiple names).
                 if (firstClass) {
-                    mProvidersByClass.put(comp, cpr);
+                    mProviderMap.putProviderByClass(comp, cpr);
                 }
-                mProvidersByName.put(name, cpr);
+                mProviderMap.putProviderByName(name, cpr);
                 incProviderCount(r, cpr);
             }
         }
@@ -6063,6 +6094,10 @@
                     return null;
                 }
                 try {
+                    if (DEBUG_MU) {
+                        Slog.v(TAG_MU, "Waiting to start provider " + cpr + " launchingApp="
+                                + cpr.launchingApp);
+                    }
                     cpr.wait();
                 } catch (InterruptedException ex) {
                 }
@@ -6073,6 +6108,7 @@
 
     public final ContentProviderHolder getContentProvider(
             IApplicationThread caller, String name) {
+        enforceNotIsolatedCaller("getContentProvider");
         if (caller == null) {
             String msg = "null IApplicationThread when getting content provider "
                     + name;
@@ -6080,7 +6116,8 @@
             throw new SecurityException(msg);
         }
 
-        return getContentProviderImpl(caller, name);
+        ContentProviderHolder contentProvider = getContentProviderImpl(caller, name);
+        return contentProvider;
     }
 
     private ContentProviderHolder getContentProviderExternal(String name) {
@@ -6092,8 +6129,10 @@
      * @param cpr
      */
     public void removeContentProvider(IApplicationThread caller, String name) {
+        enforceNotIsolatedCaller("removeContentProvider");
         synchronized (this) {
-            ContentProviderRecord cpr = mProvidersByName.get(name);
+            int userId = UserId.getUserId(Binder.getCallingUid());
+            ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
             if(cpr == null) {
                 // remove from mProvidersByClass
                 if (DEBUG_PROVIDER) Slog.v(TAG, name +
@@ -6108,8 +6147,11 @@
             }
             //update content provider record entry info
             ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
-            ContentProviderRecord localCpr = mProvidersByClass.get(comp);
-            if (localCpr.proc == r) {
+            ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
+            if (DEBUG_PROVIDER) Slog.v(TAG, "Removing provider requested by "
+                    + r.info.processName + " from process "
+                    + localCpr.appInfo.processName);
+            if (localCpr.launchingApp == r) {
                 //should not happen. taken care of as a local provider
                 Slog.w(TAG, "removeContentProvider called on local provider: "
                         + cpr.info.name + " in process " + r.processName);
@@ -6124,7 +6166,8 @@
 
     private void removeContentProviderExternal(String name) {
         synchronized (this) {
-            ContentProviderRecord cpr = mProvidersByName.get(name);
+            ContentProviderRecord cpr = mProviderMap.getProviderByName(name,
+                    Binder.getOrigCallingUser());
             if(cpr == null) {
                 //remove from mProvidersByClass
                 if(localLOGV) Slog.v(TAG, name+" content provider not found in providers list");
@@ -6133,7 +6176,8 @@
 
             //update content provider record entry info
             ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
-            ContentProviderRecord localCpr = mProvidersByClass.get(comp);
+            ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp,
+                    Binder.getOrigCallingUser());
             localCpr.externals--;
             if (localCpr.externals < 0) {
                 Slog.e(TAG, "Externals < 0 for content provider " + localCpr);
@@ -6148,8 +6192,11 @@
             return;
         }
 
+        enforceNotIsolatedCaller("publishContentProviders");
         synchronized(this) {
             final ProcessRecord r = getRecordForAppLocked(caller);
+            if (DEBUG_MU)
+                Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
             if (r == null) {
                 throw new SecurityException(
                         "Unable to find app for caller " + caller
@@ -6166,12 +6213,14 @@
                     continue;
                 }
                 ContentProviderRecord dst = r.pubProviders.get(src.info.name);
+                if (DEBUG_MU)
+                    Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
                 if (dst != null) {
                     ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
-                    mProvidersByClass.put(comp, dst);
+                    mProviderMap.putProviderByClass(comp, dst);
                     String names[] = dst.info.authority.split(";");
                     for (int j = 0; j < names.length; j++) {
-                        mProvidersByName.put(names[j], dst);
+                        mProviderMap.putProviderByName(names[j], dst);
                     }
 
                     int NL = mLaunchingProviders.size();
@@ -6231,6 +6280,7 @@
      *     src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
      */
     public String getProviderMimeType(Uri uri) {
+        enforceNotIsolatedCaller("getProviderMimeType");
         final String name = uri.getAuthority();
         final long ident = Binder.clearCallingIdentity();
         ContentProviderHolder holder = null;
@@ -6258,22 +6308,52 @@
     // =========================================================
 
     final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
-            ApplicationInfo info, String customProcess) {
+            ApplicationInfo info, String customProcess, boolean isolated) {
         String proc = customProcess != null ? customProcess : info.processName;
         BatteryStatsImpl.Uid.Proc ps = null;
         BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+        int uid = info.uid;
+        if (isolated) {
+            int userId = UserId.getUserId(uid);
+            int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
+            uid = 0;
+            while (true) {
+                if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
+                        || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
+                    mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
+                }
+                uid = UserId.getUid(userId, mNextIsolatedProcessUid);
+                mNextIsolatedProcessUid++;
+                if (mIsolatedProcesses.indexOfKey(uid) < 0) {
+                    // No process for this uid, use it.
+                    break;
+                }
+                stepsLeft--;
+                if (stepsLeft <= 0) {
+                    return null;
+                }
+            }
+        }
         synchronized (stats) {
             ps = stats.getProcessStatsLocked(info.uid, proc);
         }
-        return new ProcessRecord(ps, thread, info, proc);
+        return new ProcessRecord(ps, thread, info, proc, uid);
     }
 
-    final ProcessRecord addAppLocked(ApplicationInfo info) {
-        ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
+    final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) {
+        ProcessRecord app;
+        if (!isolated) {
+            app = getProcessRecordLocked(info.processName, info.uid);
+        } else {
+            app = null;
+        }
 
         if (app == null) {
-            app = newProcessRecordLocked(null, info, null);
-            mProcessNames.put(info.processName, info.uid, app);
+            app = newProcessRecordLocked(null, info, null, isolated);
+            mProcessNames.put(info.processName, app.uid, app);
+            if (isolated) {
+                mIsolatedProcesses.put(app.uid, app);
+            }
             updateLruProcessLocked(app, true, true);
         }
 
@@ -6318,6 +6398,7 @@
     }
 
     public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
+        enforceNotIsolatedCaller("openContentUri");
         String name = uri.getAuthority();
         ContentProviderHolder cph = getContentProviderExternal(name);
         ParcelFileDescriptor pfd = null;
@@ -6386,7 +6467,7 @@
                 mMainStack.stopIfSleepingLocked();
                 final long endTime = System.currentTimeMillis() + timeout;
                 while (mMainStack.mResumedActivity != null
-                        || mMainStack.mPausingActivity != null) {
+                        || mMainStack.mPausingActivities.size() > 0) {
                     long delay = endTime - System.currentTimeMillis();
                     if (delay <= 0) {
                         Slog.w(TAG, "Activity manager shutdown timed out");
@@ -6570,24 +6651,18 @@
         }
     }
     
-    public void registerActivityWatcher(IActivityWatcher watcher) {
-        synchronized (this) {
-            mWatchers.register(watcher);
-        }
-    }
-
-    public void unregisterActivityWatcher(IActivityWatcher watcher) {
-        synchronized (this) {
-            mWatchers.unregister(watcher);
-        }
-    }
-
     public void registerProcessObserver(IProcessObserver observer) {
-        mProcessObservers.register(observer);
+        enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+                "registerProcessObserver()");
+        synchronized (this) {
+            mProcessObservers.register(observer);
+        }
     }
 
     public void unregisterProcessObserver(IProcessObserver observer) {
-        mProcessObservers.unregister(observer);
+        synchronized (this) {
+            mProcessObservers.unregister(observer);
+        }
     }
 
     public void setImmersive(IBinder token, boolean immersive) {
@@ -6611,6 +6686,7 @@
     }
 
     public boolean isTopActivityImmersive() {
+        enforceNotIsolatedCaller("startActivity");
         synchronized (this) {
             ActivityRecord r = mMainStack.topRunningActivityLocked(null);
             return (r != null) ? r.immersive : false;
@@ -6916,8 +6992,10 @@
                             };
                         }
                         Slog.i(TAG, "Sending system update to: " + intent.getComponent());
+                        /* TODO: Send this to all users */
                         broadcastIntentLocked(null, null, intent, null, finisher,
-                                0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
+                                0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID,
+                                Process.SYSTEM_UID);
                         if (finisher != null) {
                             mWaitingUpdate = true;
                         }
@@ -7020,7 +7098,7 @@
                                 = (ApplicationInfo)apps.get(i);
                             if (info != null &&
                                     !info.packageName.equals("android")) {
-                                addAppLocked(info);
+                                addAppLocked(info, false);
                             }
                         }
                     }
@@ -7119,14 +7197,18 @@
     private boolean handleAppCrashLocked(ProcessRecord app) {
         long now = SystemClock.uptimeMillis();
 
-        Long crashTime = mProcessCrashTimes.get(app.info.processName,
-                app.info.uid);
+        Long crashTime;
+        if (!app.isolated) {
+            crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);
+        } else {
+            crashTime = null;
+        }
         if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
             // This process loses!
             Slog.w(TAG, "Process " + app.info.processName
                     + " has crashed too many times: killing!");
             EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
-                    app.info.processName, app.info.uid);
+                    app.info.processName, app.uid);
             for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
                 ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
                 if (r.app == app) {
@@ -7140,11 +7222,15 @@
                 // explicitly does so...  but for persistent process, we really
                 // need to keep it running.  If a persistent process is actually
                 // repeatedly crashing, then badness for everyone.
-                EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
+                EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.uid,
                         app.info.processName);
-                mBadProcesses.put(app.info.processName, app.info.uid, now);
+                if (!app.isolated) {
+                    // XXX We don't have a way to mark isolated processes
+                    // as bad, since they don't have a peristent identity.
+                    mBadProcesses.put(app.info.processName, app.uid, now);
+                    mProcessCrashTimes.remove(app.info.processName, app.uid);
+                }
                 app.bad = true;
-                mProcessCrashTimes.remove(app.info.processName, app.info.uid);
                 app.removed = true;
                 // Don't let services in this process be restarted and potentially
                 // annoy the user repeatedly.  Unless it is persistent, since those
@@ -7216,7 +7302,12 @@
             }
         }
 
-        mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
+        if (!app.isolated) {
+            // XXX Can't keep track of crash times for isolated processes,
+            // because they don't have a perisistent identity.
+            mProcessCrashTimes.put(app.info.processName, app.uid, now);
+        }
+
         return true;
     }
 
@@ -7227,28 +7318,8 @@
     }
 
     void skipCurrentReceiverLocked(ProcessRecord app) {
-        boolean reschedule = false;
-        BroadcastRecord r = app.curReceiver;
-        if (r != null) {
-            // The current broadcast is waiting for this app's receiver
-            // to be finished.  Looks like that's not going to happen, so
-            // let the broadcast continue.
-            logBroadcastReceiverDiscardLocked(r);
-            finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
-            reschedule = true;
-        }
-        r = mPendingBroadcast;
-        if (r != null && r.curApp == app) {
-            if (DEBUG_BROADCAST) Slog.v(TAG,
-                    "skip & discard pending app " + r);
-            logBroadcastReceiverDiscardLocked(r);
-            finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
-            reschedule = true;
-        }
-        if (reschedule) {
-            scheduleBroadcastsLocked();
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            queue.skipCurrentReceiverLocked(app);
         }
     }
 
@@ -7734,8 +7805,10 @@
 
         Intent appErrorIntent = null;
         synchronized (this) {
-            if (r != null) {
-                mProcessCrashTimes.put(r.info.processName, r.info.uid,
+            if (r != null && !r.isolated) {
+                // XXX Can't keep track of crash time for isolated processes,
+                // since they don't have a persistent identity.
+                mProcessCrashTimes.put(r.info.processName, r.uid,
                         SystemClock.uptimeMillis());
             }
             if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
@@ -7798,6 +7871,7 @@
     }
 
     public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
+        enforceNotIsolatedCaller("getProcessesInErrorState");
         // assume our apps are happy - lazy create the list
         List<ActivityManager.ProcessErrorStateInfo> errList = null;
 
@@ -7860,6 +7934,7 @@
     }
 
     public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
+        enforceNotIsolatedCaller("getRunningAppProcesses");
         // Lazy instantiation of list
         List<ActivityManager.RunningAppProcessInfo> runList = null;
         synchronized (this) {
@@ -7905,6 +7980,7 @@
     }
 
     public List<ApplicationInfo> getRunningExternalApplications() {
+        enforceNotIsolatedCaller("getRunningExternalApplications");
         List<ActivityManager.RunningAppProcessInfo> runningApps = getRunningAppProcesses();
         List<ApplicationInfo> retList = new ArrayList<ApplicationInfo>();
         if (runningApps != null && runningApps.size() > 0) {
@@ -8198,8 +8274,13 @@
         }
 
         pw.println(" ");
-        if (mMainStack.mPausingActivity != null) {
-            pw.println("  mPausingActivity: " + mMainStack.mPausingActivity);
+        if (mMainStack.mPausingActivities.size() > 0) {
+            pw.println("  mPausingActivities: " + Arrays.toString(
+                    mMainStack.mPausingActivities.toArray()));
+        }
+        if (mMainStack.mInputPausedActivities.size() > 0) {
+            pw.println("  mInputPausedActivities: " + Arrays.toString(
+                    mMainStack.mInputPausedActivities.toArray()));
         }
         pw.println("  mResumedActivity: " + mMainStack.mResumedActivity);
         pw.println("  mFocusedActivity: " + mFocusedActivity);
@@ -8268,7 +8349,21 @@
                 }
             }
         }
-        
+
+        if (mIsolatedProcesses.size() > 0) {
+            if (needSep) pw.println(" ");
+            needSep = true;
+            pw.println("  Isolated process list (sorted by uid):");
+            for (int i=0; i<mIsolatedProcesses.size(); i++) {
+                ProcessRecord r = mIsolatedProcesses.valueAt(i);
+                if (dumpPackage != null && !dumpPackage.equals(r.info.packageName)) {
+                    continue;
+                }
+                pw.println(String.format("%sIsolated #%2d: %s",
+                        "    ", i, r.toString()));
+            }
+        }
+
         if (mLruProcesses.size() > 0) {
             if (needSep) pw.println(" ");
             needSep = true;
@@ -8563,8 +8658,14 @@
 
         if ("all".equals(name)) {
             synchronized (this) {
-                for (ServiceRecord r1 : mServices.values()) {
-                    services.add(r1);
+                try {
+                    List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
+                    for (UserInfo user : users) {
+                        for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) {
+                            services.add(r1);
+                        }
+                    }
+                } catch (RemoteException re) {
                 }
             }
         } else {
@@ -8582,18 +8683,24 @@
             }
 
             synchronized (this) {
-                for (ServiceRecord r1 : mServices.values()) {
-                    if (componentName != null) {
-                        if (r1.name.equals(componentName)) {
-                            services.add(r1);
+                try {
+                    List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
+                    for (UserInfo user : users) {
+                        for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) {
+                            if (componentName != null) {
+                                if (r1.name.equals(componentName)) {
+                                    services.add(r1);
+                                }
+                            } else if (name != null) {
+                                if (r1.name.flattenToString().contains(name)) {
+                                    services.add(r1);
+                                }
+                            } else if (System.identityHashCode(r1) == objectId) {
+                                services.add(r1);
+                            }
                         }
-                    } else if (name != null) {
-                        if (r1.name.flattenToString().contains(name)) {
-                            services.add(r1);
-                        }
-                    } else if (System.identityHashCode(r1) == objectId) {
-                        services.add(r1);
                     }
+                } catch (RemoteException re) {
                 }
             }
         }
@@ -8661,98 +8768,7 @@
      */
     protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
             int opti, boolean dumpAll) {
-        ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
-
-        if ("all".equals(name)) {
-            synchronized (this) {
-                for (ContentProviderRecord r1 : mProvidersByClass.values()) {
-                    providers.add(r1);
-                }
-            }
-        } else {
-            ComponentName componentName = name != null
-                    ? ComponentName.unflattenFromString(name) : null;
-            int objectId = 0;
-            if (componentName == null) {
-                // Not a '/' separated full component name; maybe an object ID?
-                try {
-                    objectId = Integer.parseInt(name, 16);
-                    name = null;
-                    componentName = null;
-                } catch (RuntimeException e) {
-                }
-            }
-
-            synchronized (this) {
-                for (ContentProviderRecord r1 : mProvidersByClass.values()) {
-                    if (componentName != null) {
-                        if (r1.name.equals(componentName)) {
-                            providers.add(r1);
-                        }
-                    } else if (name != null) {
-                        if (r1.name.flattenToString().contains(name)) {
-                            providers.add(r1);
-                        }
-                    } else if (System.identityHashCode(r1) == objectId) {
-                        providers.add(r1);
-                    }
-                }
-            }
-        }
-
-        if (providers.size() <= 0) {
-            return false;
-        }
-
-        boolean needSep = false;
-        for (int i=0; i<providers.size(); i++) {
-            if (needSep) {
-                pw.println();
-            }
-            needSep = true;
-            dumpProvider("", fd, pw, providers.get(i), args, dumpAll);
-        }
-        return true;
-    }
-
-    /**
-     * Invokes IApplicationThread.dumpProvider() on the thread of the specified provider if
-     * there is a thread associated with the provider.
-     */
-    private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw,
-            final ContentProviderRecord r, String[] args, boolean dumpAll) {
-        String innerPrefix = prefix + "  ";
-        synchronized (this) {
-            pw.print(prefix); pw.print("PROVIDER ");
-                    pw.print(r);
-                    pw.print(" pid=");
-                    if (r.proc != null) pw.println(r.proc.pid);
-                    else pw.println("(not running)");
-            if (dumpAll) {
-                r.dump(pw, innerPrefix);
-            }
-        }
-        if (r.proc != null && r.proc.thread != null) {
-            pw.println("    Client:");
-            pw.flush();
-            try {
-                TransferPipe tp = new TransferPipe();
-                try {
-                    r.proc.thread.dumpProvider(
-                            tp.getWriteFd().getFileDescriptor(), r.provider.asBinder(), args);
-                    tp.setBufferPrefix("      ");
-                    // Short timeout, since blocking here can
-                    // deadlock with the application.
-                    tp.go(fd, 2000);
-                } finally {
-                    tp.kill();
-                }
-            } catch (IOException ex) {
-                pw.println("      Failure while dumping the provider: " + ex);
-            } catch (RemoteException ex) {
-                pw.println("      Got a RemoteException while dumping the service");
-            }
-        }
+        return mProviderMap.dumpProvider(fd, pw, name, args, opti, dumpAll);
     }
 
     static class ItemMatcher {
@@ -8971,84 +8987,11 @@
                 needSep = true;
             }
         }
-        
-        if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
-                || mPendingBroadcast != null) {
-            boolean printed = false;
-            for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
-                BroadcastRecord br = mParallelBroadcasts.get(i);
-                if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
-                    continue;
-                }
-                if (!printed) {
-                    if (needSep) {
-                        pw.println();
-                    }
-                    needSep = true;
-                    pw.println("  Active broadcasts:");
-                }
-                pw.println("  Broadcast #" + i + ":");
-                br.dump(pw, "    ");
-            }
-            printed = false;
-            for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
-                BroadcastRecord br = mOrderedBroadcasts.get(i);
-                if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
-                    continue;
-                }
-                if (!printed) {
-                    if (needSep) {
-                        pw.println();
-                    }
-                    needSep = true;
-                    pw.println("  Active ordered broadcasts:");
-                }
-                pw.println("  Ordered Broadcast #" + i + ":");
-                mOrderedBroadcasts.get(i).dump(pw, "    ");
-            }
-            if (dumpPackage == null || (mPendingBroadcast != null
-                    && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
-                if (needSep) {
-                    pw.println();
-                }
-                pw.println("  Pending broadcast:");
-                if (mPendingBroadcast != null) {
-                    mPendingBroadcast.dump(pw, "    ");
-                } else {
-                    pw.println("    (null)");
-                }
-                needSep = true;
-            }
+
+        for (BroadcastQueue q : mBroadcastQueues) {
+            needSep = q.dumpLocked(fd, pw, args, opti, dumpAll, dumpPackage, needSep);
         }
 
-        boolean printed = false;
-        for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
-            BroadcastRecord r = mBroadcastHistory[i];
-            if (r == null) {
-                break;
-            }
-            if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
-                continue;
-            }
-            if (!printed) {
-                if (needSep) {
-                    pw.println();
-                }
-                needSep = true;
-                pw.println("  Historical broadcasts:");
-                printed = true;
-            }
-            if (dumpAll) {
-                pw.print("  Historical Broadcast #"); pw.print(i); pw.println(":");
-                r.dump(pw, "    ");
-            } else {
-                if (i >= 50) {
-                    pw.println("  ...");
-                    break;
-                }
-                pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
-            }
-        }
         needSep = true;
         
         if (mStickyBroadcasts != null && dumpPackage == null) {
@@ -9085,7 +9028,10 @@
         
         if (dumpAll) {
             pw.println();
-            pw.println("  mBroadcastsScheduled=" + mBroadcastsScheduled);
+            for (BroadcastQueue queue : mBroadcastQueues) {
+                pw.println("  mBroadcastsScheduled [" + queue.mQueueName + "]="
+                        + queue.mBroadcastsScheduled);
+            }
             pw.println("  mHandler:");
             mHandler.dump(new PrintWriterPrinter(pw), "    ");
             needSep = true;
@@ -9105,75 +9051,87 @@
         matcher.build(args, opti);
 
         pw.println("ACTIVITY MANAGER SERVICES (dumpsys activity services)");
-        if (mServices.size() > 0) {
-            boolean printed = false;
-            long nowReal = SystemClock.elapsedRealtime();
-            Iterator<ServiceRecord> it = mServices.values().iterator();
-            needSep = false;
-            while (it.hasNext()) {
-                ServiceRecord r = it.next();
-                if (!matcher.match(r, r.name)) {
-                    continue;
-                }
-                if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
-                    continue;
-                }
-                if (!printed) {
-                    pw.println("  Active services:");
-                    printed = true;
-                }
-                if (needSep) {
-                    pw.println();
-                }
-                pw.print("  * "); pw.println(r);
-                if (dumpAll) {
-                    r.dump(pw, "    ");
-                    needSep = true;
-                } else {
-                    pw.print("    app="); pw.println(r.app);
-                    pw.print("    created=");
-                        TimeUtils.formatDuration(r.createTime, nowReal, pw);
-                        pw.print(" started="); pw.print(r.startRequested);
-                        pw.print(" connections="); pw.println(r.connections.size());
-                    if (r.connections.size() > 0) {
-                        pw.println("    Connections:");
-                        for (ArrayList<ConnectionRecord> clist : r.connections.values()) {
-                            for (int i=0; i<clist.size(); i++) {
-                                ConnectionRecord conn = clist.get(i);
-                                pw.print("      ");
-                                pw.print(conn.binding.intent.intent.getIntent().toShortString(
-                                        false, false, false));
-                                pw.print(" -> ");
-                                ProcessRecord proc = conn.binding.client;
-                                pw.println(proc != null ? proc.toShortString() : "null");
+        try {
+            List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
+            for (UserInfo user : users) {
+                if (mServiceMap.getAllServices(user.id).size() > 0) {
+                    boolean printed = false;
+                    long nowReal = SystemClock.elapsedRealtime();
+                    Iterator<ServiceRecord> it = mServiceMap.getAllServices(
+                            user.id).iterator();
+                    needSep = false;
+                    while (it.hasNext()) {
+                        ServiceRecord r = it.next();
+                        if (!matcher.match(r, r.name)) {
+                            continue;
+                        }
+                        if (dumpPackage != null && !dumpPackage.equals(r.appInfo.packageName)) {
+                            continue;
+                        }
+                        if (!printed) {
+                            pw.println("  Active services:");
+                            printed = true;
+                        }
+                        if (needSep) {
+                            pw.println();
+                        }
+                        pw.print("  * ");
+                        pw.println(r);
+                        if (dumpAll) {
+                            r.dump(pw, "    ");
+                            needSep = true;
+                        } else {
+                            pw.print("    app=");
+                            pw.println(r.app);
+                            pw.print("    created=");
+                            TimeUtils.formatDuration(r.createTime, nowReal, pw);
+                            pw.print(" started=");
+                            pw.print(r.startRequested);
+                            pw.print(" connections=");
+                            pw.println(r.connections.size());
+                            if (r.connections.size() > 0) {
+                                pw.println("    Connections:");
+                                for (ArrayList<ConnectionRecord> clist : r.connections.values()) {
+                                    for (int i = 0; i < clist.size(); i++) {
+                                        ConnectionRecord conn = clist.get(i);
+                                        pw.print("      ");
+                                        pw.print(conn.binding.intent.intent.getIntent()
+                                                .toShortString(false, false, false));
+                                        pw.print(" -> ");
+                                        ProcessRecord proc = conn.binding.client;
+                                        pw.println(proc != null ? proc.toShortString() : "null");
+                                    }
+                                }
                             }
                         }
-                    }
-                }
-                if (dumpClient && r.app != null && r.app.thread != null) {
-                    pw.println("    Client:");
-                    pw.flush();
-                    try {
-                        TransferPipe tp = new TransferPipe();
-                        try {
-                            r.app.thread.dumpService(
-                                    tp.getWriteFd().getFileDescriptor(), r, args);
-                            tp.setBufferPrefix("      ");
-                            // Short timeout, since blocking here can
-                            // deadlock with the application.
-                            tp.go(fd, 2000);
-                        } finally {
-                            tp.kill();
+                        if (dumpClient && r.app != null && r.app.thread != null) {
+                            pw.println("    Client:");
+                            pw.flush();
+                            try {
+                                TransferPipe tp = new TransferPipe();
+                                try {
+                                    r.app.thread.dumpService(tp.getWriteFd().getFileDescriptor(),
+                                            r, args);
+                                    tp.setBufferPrefix("      ");
+                                    // Short timeout, since blocking here can
+                                    // deadlock with the application.
+                                    tp.go(fd, 2000);
+                                } finally {
+                                    tp.kill();
+                                }
+                            } catch (IOException e) {
+                                pw.println("      Failure while dumping the service: " + e);
+                            } catch (RemoteException e) {
+                                pw.println("      Got a RemoteException while dumping the service");
+                            }
+                            needSep = true;
                         }
-                    } catch (IOException e) {
-                        pw.println("      Failure while dumping the service: " + e);
-                    } catch (RemoteException e) {
-                        pw.println("      Got a RemoteException while dumping the service");
                     }
-                    needSep = true;
+                    needSep = printed;
                 }
             }
-            needSep = printed;
+        } catch (RemoteException re) {
+
         }
 
         if (mPendingServices.size() > 0) {
@@ -9283,76 +9241,8 @@
         matcher.build(args, opti);
 
         pw.println("ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)");
-        if (mProvidersByClass.size() > 0) {
-            boolean printed = false;
-            Iterator<Map.Entry<ComponentName, ContentProviderRecord>> it
-                    = mProvidersByClass.entrySet().iterator();
-            while (it.hasNext()) {
-                Map.Entry<ComponentName, ContentProviderRecord> e = it.next();
-                ContentProviderRecord r = e.getValue();
-                ComponentName comp = e.getKey();
-                String cls = comp.getClassName();
-                int end = cls.lastIndexOf('.');
-                if (end > 0 && end < (cls.length()-2)) {
-                    cls = cls.substring(end+1);
-                }
-                if (!matcher.match(r, comp)) {
-                    continue;
-                }
-                if (dumpPackage != null && !dumpPackage.equals(comp.getPackageName())) {
-                    continue;
-                }
-                if (!printed) {
-                    if (needSep) pw.println(" ");
-                    needSep = true;
-                    pw.println("  Published content providers (by class):");
-                    printed = true;
-                }
-                pw.print("  * "); pw.print(cls); pw.print(" (");
-                        pw.print(comp.flattenToShortString()); pw.println(")");
-                if (dumpAll) {
-                    r.dump(pw, "      ");
-                } else {
-                    if (r.proc != null) {
-                        pw.print("      "); pw.println(r.proc);
-                    } else {
-                        pw.println();
-                    }
-                    if (r.clients.size() > 0) {
-                        pw.println("      Clients:");
-                        for (ProcessRecord cproc : r.clients) {
-                            pw.print("        - "); pw.println(cproc);
-                        }
-                    }
-                }
-            }
-        }
-    
-        if (dumpAll) {
-            if (mProvidersByName.size() > 0) {
-                boolean printed = false;
-                Iterator<Map.Entry<String, ContentProviderRecord>> it
-                        = mProvidersByName.entrySet().iterator();
-                while (it.hasNext()) {
-                    Map.Entry<String, ContentProviderRecord> e = it.next();
-                    ContentProviderRecord r = e.getValue();
-                    if (!matcher.match(r, r.name)) {
-                        continue;
-                    }
-                    if (dumpPackage != null && !dumpPackage.equals(r.name.getPackageName())) {
-                        continue;
-                    }
-                    if (!printed) {
-                        if (needSep) pw.println(" ");
-                        needSep = true;
-                        pw.println("  Authority to provider mappings:");
-                        printed = true;
-                    }
-                    pw.print("  "); pw.print(e.getKey()); pw.println(":");
-                    pw.print("    "); pw.println(r);
-                }
-            }
-        }
+
+        mProviderMap.dumpProvidersLocked(pw, dumpAll);
 
         if (mLaunchingProviders.size() > 0) {
             boolean printed = false;
@@ -10167,6 +10057,7 @@
                     sr.stats.stopLaunchedLocked();
                 }
                 sr.app = null;
+                sr.isolatedProc = null;
                 sr.executeNesting = 0;
                 if (mStoppingServices.remove(sr)) {
                     if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr);
@@ -10238,10 +10129,10 @@
             cpr.notifyAll();
         }
         
-        mProvidersByClass.remove(cpr.name);
+        mProviderMap.removeProviderByClass(cpr.name, UserId.getUserId(cpr.uid));
         String names[] = cpr.info.authority.split(";");
         for (int j = 0; j < names.length; j++) {
-            mProvidersByName.remove(names[j]);
+            mProviderMap.removeProviderByName(names[j], UserId.getUserId(cpr.uid));
         }
         
         Iterator<ProcessRecord> cit = cpr.clients.iterator();
@@ -10402,10 +10293,11 @@
             return;
         }
 
-        if (!app.persistent) {
+        if (!app.persistent || app.isolated) {
             if (DEBUG_PROCESSES) Slog.v(TAG,
                     "Removing non-persistent process during cleanup: " + app);
-            mProcessNames.remove(app.processName, app.info.uid);
+            mProcessNames.remove(app.processName, app.uid);
+            mIsolatedProcesses.remove(app.uid);
             if (mHeavyWeightProcess == app) {
                 mHeavyWeightProcess = null;
                 mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG);
@@ -10430,10 +10322,10 @@
             mPreviousProcess = null;
         }
 
-        if (restart) {
+        if (restart && !app.isolated) {
             // We have components that still need to be running in the
             // process, so re-launch it.
-            mProcessNames.put(app.processName, app.info.uid, app);
+            mProcessNames.put(app.processName, app.uid, app);
             startProcessLocked(app, "restart", app.processName);
         } else if (app.pid > 0 && app.pid != MY_PID) {
             // Goodbye!
@@ -10513,12 +10405,15 @@
     
     public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
             int flags) {
+        enforceNotIsolatedCaller("getServices");
         synchronized (this) {
             ArrayList<ActivityManager.RunningServiceInfo> res
                     = new ArrayList<ActivityManager.RunningServiceInfo>();
             
-            if (mServices.size() > 0) {
-                Iterator<ServiceRecord> it = mServices.values().iterator();
+            int userId = UserId.getUserId(Binder.getCallingUid());
+            if (mServiceMap.getAllServices(userId).size() > 0) {
+                Iterator<ServiceRecord> it
+                        = mServiceMap.getAllServices(userId).iterator();
                 while (it.hasNext() && res.size() < maxNum) {
                     res.add(makeRunningServiceInfoLocked(it.next()));
                 }
@@ -10537,8 +10432,10 @@
     }
 
     public PendingIntent getRunningServiceControlPanel(ComponentName name) {
+        enforceNotIsolatedCaller("getRunningServiceControlPanel");
         synchronized (this) {
-            ServiceRecord r = mServices.get(name);
+            int userId = UserId.getUserId(Binder.getCallingUid());
+            ServiceRecord r = mServiceMap.getServiceByName(name, userId);
             if (r != null) {
                 for (ArrayList<ConnectionRecord> conn : r.connections.values()) {
                     for (int i=0; i<conn.size(); i++) {
@@ -10554,7 +10451,7 @@
     
     private final ServiceRecord findServiceLocked(ComponentName name,
             IBinder token) {
-        ServiceRecord r = mServices.get(name);
+        ServiceRecord r = mServiceMap.getServiceByName(name, Binder.getOrigCallingUser());
         return r == token ? r : null;
     }
 
@@ -10572,11 +10469,11 @@
             String resolvedType) {
         ServiceRecord r = null;
         if (service.getComponent() != null) {
-            r = mServices.get(service.getComponent());
+            r = mServiceMap.getServiceByName(service.getComponent(), Binder.getOrigCallingUser());
         }
         if (r == null) {
             Intent.FilterComparison filter = new Intent.FilterComparison(service);
-            r = mServicesByIntent.get(filter);
+            r = mServiceMap.getServiceByIntent(filter, Binder.getOrigCallingUser());
         }
 
         if (r == null) {
@@ -10592,7 +10489,7 @@
 
                 ComponentName name = new ComponentName(
                         sInfo.applicationInfo.packageName, sInfo.name);
-                r = mServices.get(name);
+                r = mServiceMap.getServiceByName(name, Binder.getOrigCallingUser());
             } catch (RemoteException ex) {
                 // pm is in same process, this will never happen.
             }
@@ -10637,13 +10534,19 @@
     }
 
     private ServiceLookupResult retrieveServiceLocked(Intent service,
-            String resolvedType, int callingPid, int callingUid) {
+            String resolvedType, int callingPid, int callingUid, int userId) {
         ServiceRecord r = null;
+        if (DEBUG_SERVICE)
+            Slog.v(TAG, "retrieveServiceLocked: " + service + " type=" + resolvedType
+                    + " callingUid=" + callingUid);
+
         if (service.getComponent() != null) {
-            r = mServices.get(service.getComponent());
+            r = mServiceMap.getServiceByName(service.getComponent(), userId);
         }
-        Intent.FilterComparison filter = new Intent.FilterComparison(service);
-        r = mServicesByIntent.get(filter);
+        if (r == null) {
+            Intent.FilterComparison filter = new Intent.FilterComparison(service);
+            r = mServiceMap.getServiceByIntent(filter, userId);
+        }
         if (r == null) {
             try {
                 ResolveInfo rInfo =
@@ -10656,12 +10559,15 @@
                           ": not found");
                     return null;
                 }
-
+                if (userId > 0) {
+                    sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo, userId);
+                }
                 ComponentName name = new ComponentName(
                         sInfo.applicationInfo.packageName, sInfo.name);
-                r = mServices.get(name);
+                r = mServiceMap.getServiceByName(name, userId);
                 if (r == null) {
-                    filter = new Intent.FilterComparison(service.cloneFilter());
+                    Intent.FilterComparison filter = new Intent.FilterComparison(
+                            service.cloneFilter());
                     ServiceRestarter res = new ServiceRestarter();
                     BatteryStatsImpl.Uid.Pkg.Serv ss = null;
                     BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
@@ -10672,8 +10578,8 @@
                     }
                     r = new ServiceRecord(this, ss, name, filter, sInfo, res);
                     res.setService(r);
-                    mServices.put(name, r);
-                    mServicesByIntent.put(filter, r);
+                    mServiceMap.putServiceByName(name, UserId.getUserId(r.appInfo.uid), r);
+                    mServiceMap.putServiceByIntent(filter, UserId.getUserId(r.appInfo.uid), r);
                     
                     // Make sure this component isn't in the pending list.
                     int N = mPendingServices.size();
@@ -10820,7 +10726,9 @@
         if (app.thread == null) {
             throw new RemoteException();
         }
-
+        if (DEBUG_MU)
+            Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
+                    + ", ProcessRecord.uid = " + app.uid);
         r.app = app;
         r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
 
@@ -11015,33 +10923,53 @@
                     + r.packageName + ": " + e);
         }
 
+        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
         final String appName = r.processName;
-        ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
-        if (app != null && app.thread != null) {
-            try {
-                app.addPackage(r.appInfo.packageName);
-                realStartServiceLocked(r, app);
-                return true;
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Exception when starting service " + r.shortName, e);
-            }
+        ProcessRecord app;
 
-            // If a dead object exception was thrown -- fall through to
-            // restart the application.
+        if (!isolated) {
+            app = getProcessRecordLocked(appName, r.appInfo.uid);
+            if (DEBUG_MU)
+                Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
+            if (app != null && app.thread != null) {
+                try {
+                    app.addPackage(r.appInfo.packageName);
+                    realStartServiceLocked(r, app);
+                    return true;
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
+                }
+
+                // If a dead object exception was thrown -- fall through to
+                // restart the application.
+            }
+        } else {
+            // If this service runs in an isolated process, then each time
+            // we call startProcessLocked() we will get a new isolated
+            // process, starting another process if we are currently waiting
+            // for a previous process to come up.  To deal with this, we store
+            // in the service any current isolated process it is running in or
+            // waiting to have come up.
+            app = r.isolatedProc;
         }
 
         // Not running -- get it started, and enqueue this service record
         // to be executed when the app comes up.
-        if (startProcessLocked(appName, r.appInfo, true, intentFlags,
-                "service", r.name, false) == null) {
-            Slog.w(TAG, "Unable to launch app "
-                    + r.appInfo.packageName + "/"
-                    + r.appInfo.uid + " for service "
-                    + r.intent.getIntent() + ": process is bad");
-            bringDownServiceLocked(r, true);
-            return false;
+        if (app == null) {
+            if ((app=startProcessLocked(appName, r.appInfo, true, intentFlags,
+                    "service", r.name, false, isolated)) == null) {
+                Slog.w(TAG, "Unable to launch app "
+                        + r.appInfo.packageName + "/"
+                        + r.appInfo.uid + " for service "
+                        + r.intent.getIntent() + ": process is bad");
+                bringDownServiceLocked(r, true);
+                return false;
+            }
+            if (isolated) {
+                r.isolatedProc = app;
+            }
         }
-        
+
         if (!mPendingServices.contains(r)) {
             mPendingServices.add(r);
         }
@@ -11121,8 +11049,8 @@
                 System.identityHashCode(r), r.shortName,
                 (r.app != null) ? r.app.pid : -1);
 
-        mServices.remove(r.name);
-        mServicesByIntent.remove(r.intent);
+        mServiceMap.removeServiceByName(r.name, r.userId);
+        mServiceMap.removeServiceByIntent(r.intent, r.userId);
         r.totalRestartCount = 0;
         unscheduleServiceRestartLocked(r);
 
@@ -11200,7 +11128,7 @@
 
             ServiceLookupResult res =
                 retrieveServiceLocked(service, resolvedType,
-                        callingPid, callingUid);
+                        callingPid, callingUid, UserId.getUserId(callingUid));
             if (res == null) {
                 return null;
             }
@@ -11231,11 +11159,14 @@
 
     public ComponentName startService(IApplicationThread caller, Intent service,
             String resolvedType) {
+        enforceNotIsolatedCaller("startService");
         // Refuse possible leaked file descriptors
         if (service != null && service.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
+        if (DEBUG_SERVICE)
+            Slog.v(TAG, "startService: " + service + " type=" + resolvedType);
         synchronized(this) {
             final int callingPid = Binder.getCallingPid();
             final int callingUid = Binder.getCallingUid();
@@ -11250,6 +11181,8 @@
     ComponentName startServiceInPackage(int uid,
             Intent service, String resolvedType) {
         synchronized(this) {
+            if (DEBUG_SERVICE)
+                Slog.v(TAG, "startServiceInPackage: " + service + " type=" + resolvedType);
             final long origId = Binder.clearCallingIdentity();
             ComponentName res = startServiceLocked(null, service,
                     resolvedType, -1, uid);
@@ -11269,6 +11202,7 @@
 
     public int stopService(IApplicationThread caller, Intent service,
             String resolvedType) {
+        enforceNotIsolatedCaller("stopService");
         // Refuse possible leaked file descriptors
         if (service != null && service.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -11306,6 +11240,7 @@
     }
 
     public IBinder peekService(Intent service, String resolvedType) {
+        enforceNotIsolatedCaller("peekService");
         // Refuse possible leaked file descriptors
         if (service != null && service.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -11443,16 +11378,22 @@
     
     public int bindService(IApplicationThread caller, IBinder token,
             Intent service, String resolvedType,
-            IServiceConnection connection, int flags) {
+            IServiceConnection connection, int flags, int userId) {
+        enforceNotIsolatedCaller("bindService");
         // Refuse possible leaked file descriptors
         if (service != null && service.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
+        checkValidCaller(Binder.getCallingUid(), userId);
+
         synchronized(this) {
             if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
                     + " type=" + resolvedType + " conn=" + connection.asBinder()
                     + " flags=0x" + Integer.toHexString(flags));
+            if (DEBUG_MU)
+                Slog.i(TAG_MU, "bindService uid=" + Binder.getCallingUid() + " origUid="
+                        + Binder.getOrigCallingUid());
             final ProcessRecord callerApp = getRecordForAppLocked(caller);
             if (callerApp == null) {
                 throw new SecurityException(
@@ -11495,7 +11436,7 @@
             
             ServiceLookupResult res =
                 retrieveServiceLocked(service, resolvedType,
-                        Binder.getCallingPid(), Binder.getCallingUid());
+                        Binder.getCallingPid(), Binder.getCallingUid(), userId);
             if (res == null) {
                 return 0;
             }
@@ -11841,7 +11782,9 @@
                         r.callStart = false;
                     }
                 }
-                
+                if (DEBUG_MU)
+                    Slog.v(TAG_MU, "before serviceDontExecutingLocked, uid="
+                            + Binder.getOrigCallingUid());
                 final long origId = Binder.clearCallingIdentity();
                 serviceDoneExecutingLocked(r, inStopping);
                 Binder.restoreCallingIdentity(origId);
@@ -11948,7 +11891,7 @@
                     : new ComponentName("android", "FullBackupAgent");
             // startProcessLocked() returns existing proc's record if it's already running
             ProcessRecord proc = startProcessLocked(app.processName, app,
-                    false, 0, "backup", hostingName, false);
+                    false, 0, "backup", hostingName, false, false);
             if (proc == null) {
                 Slog.e(TAG, "Unable to start backup agent process " + r);
                 return false;
@@ -12072,19 +12015,30 @@
         return cur;
     }
 
-    private final void scheduleBroadcastsLocked() {
-        if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts: current="
-                + mBroadcastsScheduled);
+    boolean isPendingBroadcastProcessLocked(int pid) {
+        return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
+                || mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
+    }
 
-        if (mBroadcastsScheduled) {
-            return;
+    void skipPendingBroadcastLocked(int pid) {
+            Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
+            for (BroadcastQueue queue : mBroadcastQueues) {
+                queue.skipPendingBroadcastLocked(pid);
+            }
+    }
+
+    // The app just attached; send any pending broadcasts that it should receive
+    boolean sendPendingBroadcastsLocked(ProcessRecord app) {
+        boolean didSomething = false;
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            didSomething |= queue.sendPendingBroadcastsLocked(app);
         }
-        mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
-        mBroadcastsScheduled = true;
+        return didSomething;
     }
 
     public Intent registerReceiver(IApplicationThread caller, String callerPackage,
             IIntentReceiver receiver, IntentFilter filter, String permission) {
+        enforceNotIsolatedCaller("registerReceiver");
         synchronized(this) {
             ProcessRecord callerApp = null;
             if (caller != null) {
@@ -12162,13 +12116,12 @@
                 int N = allSticky.size();
                 for (int i=0; i<N; i++) {
                     Intent intent = (Intent)allSticky.get(i);
-                    BroadcastRecord r = new BroadcastRecord(intent, null,
+                    BroadcastQueue queue = broadcastQueueForIntent(intent);
+                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                             null, -1, -1, null, receivers, null, 0, null, null,
                             false, true, true);
-                    if (mParallelBroadcasts.size() == 0) {
-                        scheduleBroadcastsLocked();
-                    }
-                    mParallelBroadcasts.add(r);
+                    queue.enqueueParallelBroadcastLocked(r);
+                    queue.scheduleBroadcastsLocked();
                 }
             }
 
@@ -12179,38 +12132,46 @@
     public void unregisterReceiver(IIntentReceiver receiver) {
         if (DEBUG_BROADCAST) Slog.v(TAG, "Unregister receiver: " + receiver);
 
-        boolean doNext = false;
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            boolean doTrim = false;
 
-        synchronized(this) {
-            ReceiverList rl
+            synchronized(this) {
+                ReceiverList rl
                 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
-            if (rl != null) {
-                if (rl.curBroadcast != null) {
-                    BroadcastRecord r = rl.curBroadcast;
-                    doNext = finishReceiverLocked(
-                        receiver.asBinder(), r.resultCode, r.resultData,
-                        r.resultExtras, r.resultAbort, true);
-                }
+                if (rl != null) {
+                    if (rl.curBroadcast != null) {
+                        BroadcastRecord r = rl.curBroadcast;
+                        final boolean doNext = finishReceiverLocked(
+                                receiver.asBinder(), r.resultCode, r.resultData,
+                                r.resultExtras, r.resultAbort, true);
+                        if (doNext) {
+                            doTrim = true;
+                            r.queue.processNextBroadcast(false);
+                        }
+                    }
 
-                if (rl.app != null) {
-                    rl.app.receivers.remove(rl);
-                }
-                removeReceiverLocked(rl);
-                if (rl.linkedToDeath) {
-                    rl.linkedToDeath = false;
-                    rl.receiver.asBinder().unlinkToDeath(rl, 0);
+                    if (rl.app != null) {
+                        rl.app.receivers.remove(rl);
+                    }
+                    removeReceiverLocked(rl);
+                    if (rl.linkedToDeath) {
+                        rl.linkedToDeath = false;
+                        rl.receiver.asBinder().unlinkToDeath(rl, 0);
+                    }
                 }
             }
-        }
 
-        if (!doNext) {
-            return;
+            // If we actually concluded any broadcasts, we might now be able
+            // to trim the recipients' apps from our working set
+            if (doTrim) {
+                trimApplications();
+                return;
+            }
+
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
-        
-        final long origId = Binder.clearCallingIdentity();
-        processNextBroadcast(false);
-        trimApplications();
-        Binder.restoreCallingIdentity(origId);
     }
 
     void removeReceiverLocked(ReceiverList rl) {
@@ -12237,7 +12198,8 @@
             String callerPackage, Intent intent, String resolvedType,
             IIntentReceiver resultTo, int resultCode, String resultData,
             Bundle map, String requiredPermission,
-            boolean ordered, boolean sticky, int callingPid, int callingUid) {
+            boolean ordered, boolean sticky, int callingPid, int callingUid,
+            int userId) {
         intent = new Intent(intent);
 
         // By default broadcasts do not go to stopped apps.
@@ -12412,10 +12374,11 @@
                 if (ai != null) {
                     receivers = new ArrayList();
                     ResolveInfo ri = new ResolveInfo();
-                    ri.activityInfo = ai;
+                    ri.activityInfo = getActivityInfoForUser(ai, userId);
                     receivers.add(ri);
                 }
             } else {
+                // TODO: Apply userId
                 // Need to resolve the intent to interested receivers...
                 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                          == 0) {
@@ -12440,28 +12403,17 @@
             // If we are not serializing this broadcast, then send the
             // registered receivers separately so they don't wait for the
             // components to be launched.
-            BroadcastRecord r = new BroadcastRecord(intent, callerApp,
+            final BroadcastQueue queue = broadcastQueueForIntent(intent);
+            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                     callerPackage, callingPid, callingUid, requiredPermission,
                     registeredReceivers, resultTo, resultCode, resultData, map,
                     ordered, sticky, false);
             if (DEBUG_BROADCAST) Slog.v(
-                    TAG, "Enqueueing parallel broadcast " + r
-                    + ": prev had " + mParallelBroadcasts.size());
-            boolean replaced = false;
-            if (replacePending) {
-                for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
-                    if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
-                        if (DEBUG_BROADCAST) Slog.v(TAG,
-                                "***** DROPPING PARALLEL: " + intent);
-                        mParallelBroadcasts.set(i, r);
-                        replaced = true;
-                        break;
-                    }
-                }
-            }
+                    TAG, "Enqueueing parallel broadcast " + r);
+            final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
             if (!replaced) {
-                mParallelBroadcasts.add(r);
-                scheduleBroadcastsLocked();
+                queue.enqueueParallelBroadcastLocked(r);
+                queue.scheduleBroadcastsLocked();
             }
             registeredReceivers = null;
             NR = 0;
@@ -12541,32 +12493,22 @@
 
         if ((receivers != null && receivers.size() > 0)
                 || resultTo != null) {
-            BroadcastRecord r = new BroadcastRecord(intent, callerApp,
+            BroadcastQueue queue = broadcastQueueForIntent(intent);
+            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                     callerPackage, callingPid, callingUid, requiredPermission,
                     receivers, resultTo, resultCode, resultData, map, ordered,
                     sticky, false);
             if (DEBUG_BROADCAST) Slog.v(
                     TAG, "Enqueueing ordered broadcast " + r
-                    + ": prev had " + mOrderedBroadcasts.size());
+                    + ": prev had " + queue.mOrderedBroadcasts.size());
             if (DEBUG_BROADCAST) {
                 int seq = r.intent.getIntExtra("seq", -1);
                 Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
             }
-            boolean replaced = false;
-            if (replacePending) {
-                for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
-                    if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
-                        if (DEBUG_BROADCAST) Slog.v(TAG,
-                                "***** DROPPING ORDERED: " + intent);
-                        mOrderedBroadcasts.set(i, r);
-                        replaced = true;
-                        break;
-                    }
-                }
-            }
+            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); 
             if (!replaced) {
-                mOrderedBroadcasts.add(r);
-                scheduleBroadcastsLocked();
+                queue.enqueueOrderedBroadcastLocked(r);
+                queue.scheduleBroadcastsLocked();
             }
         }
 
@@ -12605,7 +12547,8 @@
     public final int broadcastIntent(IApplicationThread caller,
             Intent intent, String resolvedType, IIntentReceiver resultTo,
             int resultCode, String resultData, Bundle map,
-            String requiredPermission, boolean serialized, boolean sticky) {
+            String requiredPermission, boolean serialized, boolean sticky, int userId) {
+        enforceNotIsolatedCaller("broadcastIntent");
         synchronized(this) {
             intent = verifyBroadcastLocked(intent);
             
@@ -12616,8 +12559,8 @@
             int res = broadcastIntentLocked(callerApp,
                     callerApp != null ? callerApp.info.packageName : null,
                     intent, resolvedType, resultTo,
-                    resultCode, resultData, map, requiredPermission, serialized,
-                    sticky, callingPid, callingUid);
+                    resultCode, resultData, map, requiredPermission, serialized, sticky,
+                    callingPid, callingUid, userId);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -12626,21 +12569,21 @@
     int broadcastIntentInPackage(String packageName, int uid,
             Intent intent, String resolvedType, IIntentReceiver resultTo,
             int resultCode, String resultData, Bundle map,
-            String requiredPermission, boolean serialized, boolean sticky) {
+            String requiredPermission, boolean serialized, boolean sticky, int userId) {
         synchronized(this) {
             intent = verifyBroadcastLocked(intent);
 
             final long origId = Binder.clearCallingIdentity();
             int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
                     resultTo, resultCode, resultData, map, requiredPermission,
-                    serialized, sticky, -1, uid);
+                    serialized, sticky, -1, uid, userId);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
     }
 
-    public final void unbroadcastIntent(IApplicationThread caller,
-            Intent intent) {
+    // TODO: Use the userId; maybe mStickyBroadcasts need to be tied to the user.
+    public final void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -12673,54 +12616,14 @@
     private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
             String resultData, Bundle resultExtras, boolean resultAbort,
             boolean explicit) {
-        if (mOrderedBroadcasts.size() == 0) {
-            if (explicit) {
-                Slog.w(TAG, "finishReceiver called but no pending broadcasts");
-            }
+        final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver);
+        if (r == null) {
+            Slog.w(TAG, "finishReceiver called but not found on queue");
             return false;
         }
-        BroadcastRecord r = mOrderedBroadcasts.get(0);
-        if (r.receiver == null) {
-            if (explicit) {
-                Slog.w(TAG, "finishReceiver called but none active");
-            }
-            return false;
-        }
-        if (r.receiver != receiver) {
-            Slog.w(TAG, "finishReceiver called but active receiver is different");
-            return false;
-        }
-        int state = r.state;
-        r.state = BroadcastRecord.IDLE;
-        if (state == BroadcastRecord.IDLE) {
-            if (explicit) {
-                Slog.w(TAG, "finishReceiver called but state is IDLE");
-            }
-        }
-        r.receiver = null;
-        r.intent.setComponent(null);
-        if (r.curApp != null) {
-            r.curApp.curReceiver = null;
-        }
-        if (r.curFilter != null) {
-            r.curFilter.receiverList.curBroadcast = null;
-        }
-        r.curFilter = null;
-        r.curApp = null;
-        r.curComponent = null;
-        r.curReceiver = null;
-        mPendingBroadcast = null;
 
-        r.resultCode = resultCode;
-        r.resultData = resultData;
-        r.resultExtras = resultExtras;
-        r.resultAbort = resultAbort;
-
-        // We will process the next receiver right now if this is finishing
-        // an app receiver (which is always asynchronous) or after we have
-        // come back from calling a receiver.
-        return state == BroadcastRecord.APP_RECEIVE
-                || state == BroadcastRecord.CALL_DONE_RECEIVE;
+        return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort,
+                explicit);
     }
 
     public void finishReceiver(IBinder who, int resultCode, String resultData,
@@ -12732,615 +12635,28 @@
             throw new IllegalArgumentException("File descriptors passed in Bundle");
         }
 
-        boolean doNext;
-
         final long origId = Binder.clearCallingIdentity();
-
-        synchronized(this) {
-            doNext = finishReceiverLocked(
-                who, resultCode, resultData, resultExtras, resultAbort, true);
-        }
-
-        if (doNext) {
-            processNextBroadcast(false);
-        }
-        trimApplications();
-
-        Binder.restoreCallingIdentity(origId);
-    }
-
-    private final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
-        if (r.nextReceiver > 0) {
-            Object curReceiver = r.receivers.get(r.nextReceiver-1);
-            if (curReceiver instanceof BroadcastFilter) {
-                BroadcastFilter bf = (BroadcastFilter) curReceiver;
-                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
-                        System.identityHashCode(r),
-                        r.intent.getAction(),
-                        r.nextReceiver - 1,
-                        System.identityHashCode(bf));
-            } else {
-                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
-                        System.identityHashCode(r),
-                        r.intent.getAction(),
-                        r.nextReceiver - 1,
-                        ((ResolveInfo)curReceiver).toString());
-            }
-        } else {
-            Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
-                    + r);
-            EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
-                    System.identityHashCode(r),
-                    r.intent.getAction(),
-                    r.nextReceiver,
-                    "NONE");
-        }
-    }
-
-    private final void setBroadcastTimeoutLocked(long timeoutTime) {
-        if (! mPendingBroadcastTimeoutMessage) {
-            Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
-            mHandler.sendMessageAtTime(msg, timeoutTime);
-            mPendingBroadcastTimeoutMessage = true;
-        }
-    }
-
-    private final void cancelBroadcastTimeoutLocked() {
-        if (mPendingBroadcastTimeoutMessage) {
-            mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
-            mPendingBroadcastTimeoutMessage = false;
-        }
-    }
-
-    private final void broadcastTimeoutLocked(boolean fromMsg) {
-        if (fromMsg) {
-            mPendingBroadcastTimeoutMessage = false;
-        }
-
-        if (mOrderedBroadcasts.size() == 0) {
-            return;
-        }
-
-        long now = SystemClock.uptimeMillis();
-        BroadcastRecord r = mOrderedBroadcasts.get(0);
-        if (fromMsg) {
-            if (mDidDexOpt) {
-                // Delay timeouts until dexopt finishes.
-                mDidDexOpt = false;
-                long timeoutTime = SystemClock.uptimeMillis() + BROADCAST_TIMEOUT;
-                setBroadcastTimeoutLocked(timeoutTime);
-                return;
-            }
-            if (! mProcessesReady) {
-                // Only process broadcast timeouts if the system is ready. That way
-                // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
-                // to do heavy lifting for system up.
-                return;
-            }
-
-            long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT;
-            if (timeoutTime > now) {
-                // We can observe premature timeouts because we do not cancel and reset the
-                // broadcast timeout message after each receiver finishes.  Instead, we set up
-                // an initial timeout then kick it down the road a little further as needed
-                // when it expires.
-                if (DEBUG_BROADCAST) Slog.v(TAG,
-                        "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
-                        + timeoutTime);
-                setBroadcastTimeoutLocked(timeoutTime);
-                return;
-            }
-        }
-
-        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
-                + ", started " + (now - r.receiverTime) + "ms ago");
-        r.receiverTime = now;
-        r.anrCount++;
-
-        // Current receiver has passed its expiration date.
-        if (r.nextReceiver <= 0) {
-            Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
-            return;
-        }
-
-        ProcessRecord app = null;
-        String anrMessage = null;
-
-        Object curReceiver = r.receivers.get(r.nextReceiver-1);
-        Slog.w(TAG, "Receiver during timeout: " + curReceiver);
-        logBroadcastReceiverDiscardLocked(r);
-        if (curReceiver instanceof BroadcastFilter) {
-            BroadcastFilter bf = (BroadcastFilter)curReceiver;
-            if (bf.receiverList.pid != 0
-                    && bf.receiverList.pid != MY_PID) {
-                synchronized (this.mPidsSelfLocked) {
-                    app = this.mPidsSelfLocked.get(
-                            bf.receiverList.pid);
-                }
-            }
-        } else {
-            app = r.curApp;
-        }
-        
-        if (app != null) {
-            anrMessage = "Broadcast of " + r.intent.toString();
-        }
-
-        if (mPendingBroadcast == r) {
-            mPendingBroadcast = null;
-        }
-
-        // Move on to the next receiver.
-        finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
-                r.resultExtras, r.resultAbort, true);
-        scheduleBroadcastsLocked();
-
-        if (anrMessage != null) {
-            // Post the ANR to the handler since we do not want to process ANRs while
-            // potentially holding our lock.
-            mHandler.post(new AppNotResponding(app, anrMessage));
-        }
-    }
-
-    private final void processCurBroadcastLocked(BroadcastRecord r,
-            ProcessRecord app) throws RemoteException {
-        if (DEBUG_BROADCAST)  Slog.v(TAG,
-                "Process cur broadcast " + r + " for app " + app);
-        if (app.thread == null) {
-            throw new RemoteException();
-        }
-        r.receiver = app.thread.asBinder();
-        r.curApp = app;
-        app.curReceiver = r;
-        updateLruProcessLocked(app, true, true);
-
-        // Tell the application to launch this receiver.
-        r.intent.setComponent(r.curComponent);
-
-        boolean started = false;
         try {
-            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
-                    "Delivering to component " + r.curComponent
-                    + ": " + r);
-            ensurePackageDexOpt(r.intent.getComponent().getPackageName());
-            app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
-                    compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
-                    r.resultCode, r.resultData, r.resultExtras, r.ordered);
-            if (DEBUG_BROADCAST)  Slog.v(TAG,
-                    "Process cur broadcast " + r + " DELIVERED for app " + app);
-            started = true;
+            boolean doNext = false;
+            BroadcastRecord r = null;
+
+            synchronized(this) {
+                r = broadcastRecordForReceiverLocked(who);
+                if (r != null) {
+                    doNext = r.queue.finishReceiverLocked(r, resultCode,
+                        resultData, resultExtras, resultAbort, true);
+                }
+            }
+
+            if (doNext) {
+                r.queue.processNextBroadcast(false);
+            }
+            trimApplications();
         } finally {
-            if (!started) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Process cur broadcast " + r + ": NOT STARTED!");
-                r.receiver = null;
-                r.curApp = null;
-                app.curReceiver = null;
-            }
-        }
-
-    }
-
-    static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
-            Intent intent, int resultCode, String data, Bundle extras,
-            boolean ordered, boolean sticky) throws RemoteException {
-        // Send the intent to the receiver asynchronously using one-way binder calls.
-        if (app != null && app.thread != null) {
-            // If we have an app thread, do the call through that so it is
-            // correctly ordered with other one-way calls.
-            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
-                    data, extras, ordered, sticky);
-        } else {
-            receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
+            Binder.restoreCallingIdentity(origId);
         }
     }
     
-    private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
-            BroadcastFilter filter, boolean ordered) {
-        boolean skip = false;
-        if (filter.requiredPermission != null) {
-            int perm = checkComponentPermission(filter.requiredPermission,
-                    r.callingPid, r.callingUid, -1, true);
-            if (perm != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission Denial: broadcasting "
-                        + r.intent.toString()
-                        + " from " + r.callerPackage + " (pid="
-                        + r.callingPid + ", uid=" + r.callingUid + ")"
-                        + " requires " + filter.requiredPermission
-                        + " due to registered receiver " + filter);
-                skip = true;
-            }
-        }
-        if (r.requiredPermission != null) {
-            int perm = checkComponentPermission(r.requiredPermission,
-                    filter.receiverList.pid, filter.receiverList.uid, -1, true);
-            if (perm != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission Denial: receiving "
-                        + r.intent.toString()
-                        + " to " + filter.receiverList.app
-                        + " (pid=" + filter.receiverList.pid
-                        + ", uid=" + filter.receiverList.uid + ")"
-                        + " requires " + r.requiredPermission
-                        + " due to sender " + r.callerPackage
-                        + " (uid " + r.callingUid + ")");
-                skip = true;
-            }
-        }
-
-        if (!skip) {
-            // If this is not being sent as an ordered broadcast, then we
-            // don't want to touch the fields that keep track of the current
-            // state of ordered broadcasts.
-            if (ordered) {
-                r.receiver = filter.receiverList.receiver.asBinder();
-                r.curFilter = filter;
-                filter.receiverList.curBroadcast = r;
-                r.state = BroadcastRecord.CALL_IN_RECEIVE;
-                if (filter.receiverList.app != null) {
-                    // Bump hosting application to no longer be in background
-                    // scheduling class.  Note that we can't do that if there
-                    // isn't an app...  but we can only be in that case for
-                    // things that directly call the IActivityManager API, which
-                    // are already core system stuff so don't matter for this.
-                    r.curApp = filter.receiverList.app;
-                    filter.receiverList.app.curReceiver = r;
-                    updateOomAdjLocked();
-                }
-            }
-            try {
-                if (DEBUG_BROADCAST_LIGHT) {
-                    int seq = r.intent.getIntExtra("seq", -1);
-                    Slog.i(TAG, "Delivering to " + filter
-                            + " (seq=" + seq + "): " + r);
-                }
-                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
-                    new Intent(r.intent), r.resultCode,
-                    r.resultData, r.resultExtras, r.ordered, r.initialSticky);
-                if (ordered) {
-                    r.state = BroadcastRecord.CALL_DONE_RECEIVE;
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
-                if (ordered) {
-                    r.receiver = null;
-                    r.curFilter = null;
-                    filter.receiverList.curBroadcast = null;
-                    if (filter.receiverList.app != null) {
-                        filter.receiverList.app.curReceiver = null;
-                    }
-                }
-            }
-        }
-    }
-
-    private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
-        if (r.callingUid < 0) {
-            // This was from a registerReceiver() call; ignore it.
-            return;
-        }
-        System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
-                MAX_BROADCAST_HISTORY-1);
-        r.finishTime = SystemClock.uptimeMillis();
-        mBroadcastHistory[0] = r;
-    }
-    
-    private final void processNextBroadcast(boolean fromMsg) {
-        synchronized(this) {
-            BroadcastRecord r;
-
-            if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast: "
-                    + mParallelBroadcasts.size() + " broadcasts, "
-                    + mOrderedBroadcasts.size() + " ordered broadcasts");
-
-            updateCpuStats();
-            
-            if (fromMsg) {
-                mBroadcastsScheduled = false;
-            }
-
-            // First, deliver any non-serialized broadcasts right away.
-            while (mParallelBroadcasts.size() > 0) {
-                r = mParallelBroadcasts.remove(0);
-                r.dispatchTime = SystemClock.uptimeMillis();
-                r.dispatchClockTime = System.currentTimeMillis();
-                final int N = r.receivers.size();
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast "
-                        + r);
-                for (int i=0; i<N; i++) {
-                    Object target = r.receivers.get(i);
-                    if (DEBUG_BROADCAST)  Slog.v(TAG,
-                            "Delivering non-ordered to registered "
-                            + target + ": " + r);
-                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
-                }
-                addBroadcastToHistoryLocked(r);
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast "
-                        + r);
-            }
-
-            // Now take care of the next serialized one...
-
-            // If we are waiting for a process to come up to handle the next
-            // broadcast, then do nothing at this point.  Just in case, we
-            // check that the process we're waiting for still exists.
-            if (mPendingBroadcast != null) {
-                if (DEBUG_BROADCAST_LIGHT) {
-                    Slog.v(TAG, "processNextBroadcast: waiting for "
-                            + mPendingBroadcast.curApp);
-                }
-
-                boolean isDead;
-                synchronized (mPidsSelfLocked) {
-                    isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
-                }
-                if (!isDead) {
-                    // It's still alive, so keep waiting
-                    return;
-                } else {
-                    Slog.w(TAG, "pending app " + mPendingBroadcast.curApp
-                            + " died before responding to broadcast");
-                    mPendingBroadcast.state = BroadcastRecord.IDLE;
-                    mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
-                    mPendingBroadcast = null;
-                }
-            }
-
-            boolean looped = false;
-            
-            do {
-                if (mOrderedBroadcasts.size() == 0) {
-                    // No more broadcasts pending, so all done!
-                    scheduleAppGcsLocked();
-                    if (looped) {
-                        // If we had finished the last ordered broadcast, then
-                        // make sure all processes have correct oom and sched
-                        // adjustments.
-                        updateOomAdjLocked();
-                    }
-                    return;
-                }
-                r = mOrderedBroadcasts.get(0);
-                boolean forceReceive = false;
-
-                // Ensure that even if something goes awry with the timeout
-                // detection, we catch "hung" broadcasts here, discard them,
-                // and continue to make progress.
-                //
-                // This is only done if the system is ready so that PRE_BOOT_COMPLETED
-                // receivers don't get executed with timeouts. They're intended for
-                // one time heavy lifting after system upgrades and can take
-                // significant amounts of time.
-                int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
-                if (mProcessesReady && r.dispatchTime > 0) {
-                    long now = SystemClock.uptimeMillis();
-                    if ((numReceivers > 0) &&
-                            (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
-                        Slog.w(TAG, "Hung broadcast discarded after timeout failure:"
-                                + " now=" + now
-                                + " dispatchTime=" + r.dispatchTime
-                                + " startTime=" + r.receiverTime
-                                + " intent=" + r.intent
-                                + " numReceivers=" + numReceivers
-                                + " nextReceiver=" + r.nextReceiver
-                                + " state=" + r.state);
-                        broadcastTimeoutLocked(false); // forcibly finish this broadcast
-                        forceReceive = true;
-                        r.state = BroadcastRecord.IDLE;
-                    }
-                }
-
-                if (r.state != BroadcastRecord.IDLE) {
-                    if (DEBUG_BROADCAST) Slog.d(TAG,
-                            "processNextBroadcast() called when not idle (state="
-                            + r.state + ")");
-                    return;
-                }
-
-                if (r.receivers == null || r.nextReceiver >= numReceivers
-                        || r.resultAbort || forceReceive) {
-                    // No more receivers for this broadcast!  Send the final
-                    // result if requested...
-                    if (r.resultTo != null) {
-                        try {
-                            if (DEBUG_BROADCAST) {
-                                int seq = r.intent.getIntExtra("seq", -1);
-                                Slog.i(TAG, "Finishing broadcast " + r.intent.getAction()
-                                        + " seq=" + seq + " app=" + r.callerApp);
-                            }
-                            performReceiveLocked(r.callerApp, r.resultTo,
-                                new Intent(r.intent), r.resultCode,
-                                r.resultData, r.resultExtras, false, false);
-                            // Set this to null so that the reference
-                            // (local and remote) isnt kept in the mBroadcastHistory.
-                            r.resultTo = null;
-                        } catch (RemoteException e) {
-                            Slog.w(TAG, "Failure sending broadcast result of " + r.intent, e);
-                        }
-                    }
-                    
-                    if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
-                    cancelBroadcastTimeoutLocked();
-
-                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
-                            + r);
-                    
-                    // ... and on to the next...
-                    addBroadcastToHistoryLocked(r);
-                    mOrderedBroadcasts.remove(0);
-                    r = null;
-                    looped = true;
-                    continue;
-                }
-            } while (r == null);
-
-            // Get the next receiver...
-            int recIdx = r.nextReceiver++;
-
-            // Keep track of when this receiver started, and make sure there
-            // is a timeout message pending to kill it if need be.
-            r.receiverTime = SystemClock.uptimeMillis();
-            if (recIdx == 0) {
-                r.dispatchTime = r.receiverTime;
-                r.dispatchClockTime = System.currentTimeMillis();
-                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast "
-                        + r);
-            }
-            if (! mPendingBroadcastTimeoutMessage) {
-                long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT;
-                if (DEBUG_BROADCAST) Slog.v(TAG,
-                        "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " + timeoutTime);
-                setBroadcastTimeoutLocked(timeoutTime);
-            }
-
-            Object nextReceiver = r.receivers.get(recIdx);
-            if (nextReceiver instanceof BroadcastFilter) {
-                // Simple case: this is a registered receiver who gets
-                // a direct call.
-                BroadcastFilter filter = (BroadcastFilter)nextReceiver;
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Delivering ordered to registered "
-                        + filter + ": " + r);
-                deliverToRegisteredReceiverLocked(r, filter, r.ordered);
-                if (r.receiver == null || !r.ordered) {
-                    // The receiver has already finished, so schedule to
-                    // process the next one.
-                    if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing: ordered="
-                            + r.ordered + " receiver=" + r.receiver);
-                    r.state = BroadcastRecord.IDLE;
-                    scheduleBroadcastsLocked();
-                }
-                return;
-            }
-
-            // Hard case: need to instantiate the receiver, possibly
-            // starting its application process to host it.
-
-            ResolveInfo info =
-                (ResolveInfo)nextReceiver;
-
-            boolean skip = false;
-            int perm = checkComponentPermission(info.activityInfo.permission,
-                    r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
-                    info.activityInfo.exported);
-            if (perm != PackageManager.PERMISSION_GRANTED) {
-                if (!info.activityInfo.exported) {
-                    Slog.w(TAG, "Permission Denial: broadcasting "
-                            + r.intent.toString()
-                            + " from " + r.callerPackage + " (pid=" + r.callingPid
-                            + ", uid=" + r.callingUid + ")"
-                            + " is not exported from uid " + info.activityInfo.applicationInfo.uid
-                            + " due to receiver " + info.activityInfo.packageName
-                            + "/" + info.activityInfo.name);
-                } else {
-                    Slog.w(TAG, "Permission Denial: broadcasting "
-                            + r.intent.toString()
-                            + " from " + r.callerPackage + " (pid=" + r.callingPid
-                            + ", uid=" + r.callingUid + ")"
-                            + " requires " + info.activityInfo.permission
-                            + " due to receiver " + info.activityInfo.packageName
-                            + "/" + info.activityInfo.name);
-                }
-                skip = true;
-            }
-            if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
-                r.requiredPermission != null) {
-                try {
-                    perm = AppGlobals.getPackageManager().
-                            checkPermission(r.requiredPermission,
-                                    info.activityInfo.applicationInfo.packageName);
-                } catch (RemoteException e) {
-                    perm = PackageManager.PERMISSION_DENIED;
-                }
-                if (perm != PackageManager.PERMISSION_GRANTED) {
-                    Slog.w(TAG, "Permission Denial: receiving "
-                            + r.intent + " to "
-                            + info.activityInfo.applicationInfo.packageName
-                            + " requires " + r.requiredPermission
-                            + " due to sender " + r.callerPackage
-                            + " (uid " + r.callingUid + ")");
-                    skip = true;
-                }
-            }
-            if (r.curApp != null && r.curApp.crashing) {
-                // If the target process is crashing, just skip it.
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Skipping deliver ordered " + r + " to " + r.curApp
-                        + ": process crashing");
-                skip = true;
-            }
-
-            if (skip) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Skipping delivery of ordered " + r + " for whatever reason");
-                r.receiver = null;
-                r.curFilter = null;
-                r.state = BroadcastRecord.IDLE;
-                scheduleBroadcastsLocked();
-                return;
-            }
-
-            r.state = BroadcastRecord.APP_RECEIVE;
-            String targetProcess = info.activityInfo.processName;
-            r.curComponent = new ComponentName(
-                    info.activityInfo.applicationInfo.packageName,
-                    info.activityInfo.name);
-            r.curReceiver = info.activityInfo;
-
-            // Broadcast is being executed, its package can't be stopped.
-            try {
-                AppGlobals.getPackageManager().setPackageStoppedState(
-                        r.curComponent.getPackageName(), false);
-            } catch (RemoteException e) {
-            } catch (IllegalArgumentException e) {
-                Slog.w(TAG, "Failed trying to unstop package "
-                        + r.curComponent.getPackageName() + ": " + e);
-            }
-
-            // Is this receiver's application already running?
-            ProcessRecord app = getProcessRecordLocked(targetProcess,
-                    info.activityInfo.applicationInfo.uid);
-            if (app != null && app.thread != null) {
-                try {
-                    app.addPackage(info.activityInfo.packageName);
-                    processCurBroadcastLocked(r, app);
-                    return;
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Exception when sending broadcast to "
-                          + r.curComponent, e);
-                }
-
-                // If a dead object exception was thrown -- fall through to
-                // restart the application.
-            }
-
-            // Not running -- get it started, to be executed when the app comes up.
-            if (DEBUG_BROADCAST)  Slog.v(TAG,
-                    "Need to start app " + targetProcess + " for broadcast " + r);
-            if ((r.curApp=startProcessLocked(targetProcess,
-                    info.activityInfo.applicationInfo, true,
-                    r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
-                    "broadcast", r.curComponent,
-                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
-                            == null) {
-                // Ah, this recipient is unavailable.  Finish it if necessary,
-                // and mark the broadcast record as ready for the next.
-                Slog.w(TAG, "Unable to launch app "
-                        + info.activityInfo.applicationInfo.packageName + "/"
-                        + info.activityInfo.applicationInfo.uid + " for broadcast "
-                        + r.intent + ": process is bad");
-                logBroadcastReceiverDiscardLocked(r);
-                finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
-                        r.resultExtras, r.resultAbort, true);
-                scheduleBroadcastsLocked();
-                r.state = BroadcastRecord.IDLE;
-                return;
-            }
-
-            mPendingBroadcast = r;
-            mPendingBroadcastRecvIndex = recIdx;
-        }
-    }
-
     // =========================================================
     // INSTRUMENTATION
     // =========================================================
@@ -13348,6 +12664,7 @@
     public boolean startInstrumentation(ComponentName className,
             String profileFile, int flags, Bundle arguments,
             IInstrumentationWatcher watcher) {
+        enforceNotIsolatedCaller("startInstrumentation");
         // Refuse possible leaked file descriptors
         if (arguments != null && arguments.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Bundle");
@@ -13391,7 +12708,7 @@
             final long origId = Binder.clearCallingIdentity();
             // Instrumentation can kill and relaunch even persistent processes
             forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true);
-            ProcessRecord app = addAppLocked(ai);
+            ProcessRecord app = addAppLocked(ai, false);
             app.instrumentationClass = className;
             app.instrumentationInfo = ai;
             app.instrumentationProfileFile = profileFile;
@@ -13545,8 +12862,11 @@
      * configuration.
      * @param persistent TODO
      */
-    public boolean updateConfigurationLocked(Configuration values,
+    boolean updateConfigurationLocked(Configuration values,
             ActivityRecord starting, boolean persistent, boolean initLocale) {
+        // do nothing if we are headless
+        if (mHeadless) return true;
+
         int changes = 0;
         
         boolean kept = true;
@@ -13576,6 +12896,10 @@
                 Slog.i(TAG, "Config changed: " + newConfig);
 
                 final Configuration configCopy = new Configuration(mConfiguration);
+                
+                // TODO: If our config changes, should we auto dismiss any currently
+                // showing dialogs?
+                mShowDialogs = shouldShowDialogs(newConfig);
 
                 AttributeCache ac = AttributeCache.instance();
                 if (ac != null) {
@@ -13612,12 +12936,12 @@
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                         | Intent.FLAG_RECEIVER_REPLACE_PENDING);
                 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
-                        null, false, false, MY_PID, Process.SYSTEM_UID);
+                        null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
                 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
                     broadcastIntentLocked(null, null,
                             new Intent(Intent.ACTION_LOCALE_CHANGED),
                             null, null, 0, null, null,
-                            null, false, false, MY_PID, Process.SYSTEM_UID);
+                            null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
                 }
             }
         }
@@ -13642,6 +12966,19 @@
         
         return kept;
     }
+
+    /**
+     * Decide based on the configuration whether we should shouw the ANR,
+     * crash, etc dialogs.  The idea is that if there is no affordnace to
+     * press the on-screen buttons, we shouldn't show the dialog.
+     *
+     * A thought: SystemUI might also want to get told about this, the Power
+     * dialog / global actions also might want different behaviors.
+     */
+    private static final boolean shouldShowDialogs(Configuration config) {
+        return !(config.keyboard == Configuration.KEYBOARD_NOKEYS
+                && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH);
+    }
     
     /**
      * Save the locale.  You must be inside a synchronized (this) block.
@@ -13663,6 +13000,28 @@
     // LIFETIME MANAGEMENT
     // =========================================================
 
+    // Returns which broadcast queue the app is the current [or imminent] receiver
+    // on, or 'null' if the app is not an active broadcast recipient.
+    private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
+        BroadcastRecord r = app.curReceiver;
+        if (r != null) {
+            return r.queue;
+        }
+
+        // It's not the current receiver, but it might be starting up to become one
+        synchronized (this) {
+            for (BroadcastQueue queue : mBroadcastQueues) {
+                r = queue.mPendingBroadcast;
+                if (r != null && r.curApp == app) {
+                    // found it; report which queue it's in
+                    return queue;
+                }
+            }
+        }
+
+        return null;
+    }
+
     private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
             ProcessRecord TOP_APP, boolean recursed, boolean doingAll) {
         if (mAdjSeq == app.adjSeq) {
@@ -13728,6 +13087,7 @@
         // important to least, and assign an appropriate OOM adjustment.
         int adj;
         int schedGroup;
+        BroadcastQueue queue;
         if (app == TOP_APP) {
             // The last app on the list is the foreground app.
             adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -13739,12 +13099,14 @@
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "instrumentation";
-        } else if (app.curReceiver != null ||
-                (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
+        } else if ((queue = isReceivingBroadcast(app)) != null) {
             // An app that is currently receiving a broadcast also
-            // counts as being in the foreground.
+            // counts as being in the foreground for OOM killer purposes.
+            // It's placed in a sched group based on the nature of the
+            // broadcast as reflected by which queue it's active in.
             adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_DEFAULT;
+            schedGroup = (queue == mFgBroadcastQueue)
+                    ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
             app.adjType = "broadcast";
         } else if (app.executingServices.size() > 0) {
             // An app that is currently executing a service callback also
@@ -14185,8 +13547,13 @@
      * Returns true if things are idle enough to perform GCs.
      */
     private final boolean canGcNowLocked() {
-        return mParallelBroadcasts.size() == 0
-                && mOrderedBroadcasts.size() == 0
+        boolean processingBroadcasts = false;
+        for (BroadcastQueue q : mBroadcastQueues) {
+            if (q.mParallelBroadcasts.size() != 0 || q.mOrderedBroadcasts.size() != 0) {
+                processingBroadcasts = true;
+            }
+        }
+        return !processingBroadcasts
                 && (mSleeping || (mMainStack.mResumedActivity != null &&
                         mMainStack.mResumedActivity.idle));
     }
@@ -14488,7 +13855,13 @@
     private final ActivityRecord resumedAppLocked() {
         ActivityRecord resumedActivity = mMainStack.mResumedActivity;
         if (resumedActivity == null || resumedActivity.app == null) {
-            resumedActivity = mMainStack.mPausingActivity;
+            for (int i=mMainStack.mPausingActivities.size()-1; i>=0; i--) {
+                ActivityRecord r = mMainStack.mPausingActivities.get(i);
+                if (r.app != null) {
+                    resumedActivity = r;
+                    break;
+                }
+            }
             if (resumedActivity == null || resumedActivity.app == null) {
                 resumedActivity = mMainStack.topRunningActivityLocked(null);
             }
@@ -14568,6 +13941,20 @@
                         Process.killProcessQuiet(app.pid);
                     }
                 }
+                if (!app.killedBackground && app.isolated && app.services.size() <= 0) {
+                    // If this is an isolated process, and there are no
+                    // services running in it, then the process is no longer
+                    // needed.  We agressively kill these because we can by
+                    // definition not re-use the same process again, and it is
+                    // good to avoid having whatever code was running in them
+                    // left sitting around after no longer needed.
+                    Slog.i(TAG, "Isolated process " + app.processName
+                            + " (pid " + app.pid + ") no longer needed");
+                    EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                            app.processName, app.setAdj, "isolated not needed");
+                    app.killedBackground = true;
+                    Process.killProcessQuiet(app.pid);
+                }
             }
         }
 
@@ -14706,7 +14093,7 @@
                     
                     if (app.persistent) {
                         if (app.persistent) {
-                            addAppLocked(app.info);
+                            addAppLocked(app.info, false);
                         }
                     }
                 }
@@ -14915,7 +14302,7 @@
         synchronized (this) { }
     }
 
-    public void onCoreSettingsChange(Bundle settings) {
+    void onCoreSettingsChange(Bundle settings) {
         for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
             ProcessRecord processRecord = mLruProcesses.get(i);
             try {
@@ -14930,8 +14317,191 @@
 
     // Multi-user methods
 
-    public boolean switchUser(int userid) {
-        // TODO
+    private int mCurrentUserId;
+    private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
+    private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3);
+
+    public interface UserListener {
+        public void onUserChanged(int userId);
+
+        public void onUserAdded(int userId);
+
+        public void onUserRemoved(int userId);
+
+        public void onUserLoggedOut(int userId);
+    }
+
+    public void addUserListener(UserListener listener) {
+        synchronized (this) {
+            if (!mUserListeners.contains(listener)) {
+                mUserListeners.add(listener);
+            }
+        }
+    }
+
+    public boolean switchUser(int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != 0 && callingUid != Process.myUid()) {
+            Slog.e(TAG, "Trying to switch user from unauthorized app");
+            return false;
+        }
+        if (mCurrentUserId == userId)
+            return true;
+
+        ArrayList<UserListener> listeners;
+
+        synchronized (this) {
+            // Check if user is already logged in, otherwise check if user exists first before
+            // adding to the list of logged in users.
+            if (mLoggedInUsers.indexOfKey(userId) < 0) {
+                if (!userExists(userId)) {
+                    return false;
+                }
+                mLoggedInUsers.append(userId, userId);
+            }
+
+            mCurrentUserId = userId;
+            boolean haveActivities = mMainStack.switchUser(userId);
+            if (!haveActivities) {
+                startHomeActivityLocked(userId);
+            }
+
+            listeners = (ArrayList<UserListener>) mUserListeners.clone();
+        }
+        // Inform the listeners
+        for (UserListener listener : listeners) {
+            listener.onUserChanged(userId);
+        }
         return true;
     }
+
+    private boolean userExists(int userId) {
+        try {
+            List<UserInfo> users = AppGlobals.getPackageManager().getUsers();
+            for (UserInfo user : users) {
+                if (user.id == userId) {
+                    return true;
+                }
+            }
+        } catch (RemoteException re) {
+            // Won't happen, in same process
+        }
+
+        return false;
+    }
+
+    private void checkValidCaller(int uid, int userId) {
+        if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return;
+
+        throw new SecurityException("Caller uid=" + uid
+                + " is not privileged to communicate with user=" + userId);
+    }
+
+    private int applyUserId(int uid, int userId) {
+        return UserId.getUid(userId, uid);
+    }
+
+    private ApplicationInfo getAppInfoForUser(ApplicationInfo info, int userId) {
+        if (info == null) return null;
+        ApplicationInfo newInfo = new ApplicationInfo(info);
+        newInfo.uid = applyUserId(info.uid, userId);
+        if (newInfo.uid >= Process.FIRST_APPLICATION_UID) {
+            newInfo.dataDir = USER_DATA_DIR + userId + "/"
+                    + info.packageName;
+        }
+        return newInfo;
+    }
+
+    ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, int userId) {
+        if (aInfo == null || aInfo.applicationInfo.uid < Process.FIRST_APPLICATION_UID
+                || userId < 1) {
+            return aInfo;
+        }
+
+        ActivityInfo info = new ActivityInfo(aInfo);
+        info.applicationInfo = getAppInfoForUser(info.applicationInfo, userId);
+        return info;
+    }
+
+    static class ServiceMap {
+
+        private final SparseArray<HashMap<ComponentName, ServiceRecord>> mServicesByNamePerUser
+                = new SparseArray<HashMap<ComponentName, ServiceRecord>>();
+        private final SparseArray<HashMap<Intent.FilterComparison, ServiceRecord>>
+                mServicesByIntentPerUser = new SparseArray<
+                    HashMap<Intent.FilterComparison, ServiceRecord>>();
+
+        ServiceRecord getServiceByName(ComponentName name, int callingUser) {
+            // TODO: Deal with global services
+            if (DEBUG_MU)
+                Slog.v(TAG_MU, "getServiceByName(" + name + "), callingUser = " + callingUser);
+            return getServices(callingUser).get(name);
+        }
+
+        ServiceRecord getServiceByName(ComponentName name) {
+            return getServiceByName(name, -1);
+        }
+
+        ServiceRecord getServiceByIntent(Intent.FilterComparison filter, int callingUser) {
+            // TODO: Deal with global services
+            if (DEBUG_MU)
+                Slog.v(TAG_MU, "getServiceByIntent(" + filter + "), callingUser = " + callingUser);
+            return getServicesByIntent(callingUser).get(filter);
+        }
+
+        ServiceRecord getServiceByIntent(Intent.FilterComparison filter) {
+            return getServiceByIntent(filter, -1);
+        }
+
+        void putServiceByName(ComponentName name, int callingUser, ServiceRecord value) {
+            // TODO: Deal with global services
+            getServices(callingUser).put(name, value);
+        }
+
+        void putServiceByIntent(Intent.FilterComparison filter, int callingUser,
+                ServiceRecord value) {
+            // TODO: Deal with global services
+            getServicesByIntent(callingUser).put(filter, value);
+        }
+
+        void removeServiceByName(ComponentName name, int callingUser) {
+            // TODO: Deal with global services
+            ServiceRecord removed = getServices(callingUser).remove(name);
+            if (DEBUG_MU)
+                Slog.v(TAG, "removeServiceByName user=" + callingUser + " name=" + name
+                        + " removed=" + removed);
+        }
+
+        void removeServiceByIntent(Intent.FilterComparison filter, int callingUser) {
+            // TODO: Deal with global services
+            ServiceRecord removed = getServicesByIntent(callingUser).remove(filter);
+            if (DEBUG_MU)
+                Slog.v(TAG_MU, "removeServiceByIntent user=" + callingUser + " intent=" + filter
+                        + " removed=" + removed);
+        }
+
+        Collection<ServiceRecord> getAllServices(int callingUser) {
+            // TODO: Deal with global services
+            return getServices(callingUser).values();
+        }
+
+        private HashMap<ComponentName, ServiceRecord> getServices(int callingUser) {
+            HashMap map = mServicesByNamePerUser.get(callingUser);
+            if (map == null) {
+                map = new HashMap<ComponentName, ServiceRecord>();
+                mServicesByNamePerUser.put(callingUser, map);
+            }
+            return map;
+        }
+
+        private HashMap<Intent.FilterComparison, ServiceRecord> getServicesByIntent(
+                int callingUser) {
+            HashMap map = mServicesByIntentPerUser.get(callingUser);
+            if (map == null) {
+                map = new HashMap<Intent.FilterComparison, ServiceRecord>();
+                mServicesByIntentPerUser.put(callingUser, map);
+            }
+            return map;
+        }
+    }
 }
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index c819114..977ee84 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -25,6 +25,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.res.CompatibilityInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.os.Build;
@@ -34,6 +35,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.UserId;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -55,6 +57,7 @@
     final IApplicationToken.Stub appToken; // window manager token
     final ActivityInfo info; // all about me
     final int launchedFromUid; // always the uid who started the activity.
+    final int userId;          // Which user is this running for?
     final Intent intent;    // the original intent that generated us
     final ComponentName realActivity;  // the intent component, or target of an alias.
     final String shortComponentName; // the short component name of the intent
@@ -124,6 +127,7 @@
         pw.print(prefix); pw.print("packageName="); pw.print(packageName);
                 pw.print(" processName="); pw.println(processName);
         pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
+        pw.print(prefix); pw.print("userId="); pw.print(userId);
                 pw.print(" app="); pw.println(app);
         pw.print(prefix); pw.println(intent.toInsecureString());
         pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask);
@@ -281,6 +285,7 @@
         appToken = new Token(this);
         info = aInfo;
         launchedFromUid = _launchedFromUid;
+        userId = UserId.getUserId(aInfo.applicationInfo.uid);
         intent = _intent;
         shortComponentName = _intent.getComponent().flattenToShortString();
         resolvedType = _resolvedType;
@@ -597,6 +602,7 @@
     
     public void windowsDrawn() {
         synchronized(service) {
+            stack.reportActivityDrawnLocked(this);
             if (launchTime != 0) {
                 final long curTime = SystemClock.uptimeMillis();
                 final long thisTime = curTime - launchTime;
@@ -685,7 +691,9 @@
             // Hmmm, who might we be waiting for?
             r = stack.mResumedActivity;
             if (r == null) {
-                r = stack.mPausingActivity;
+                if (stack.mPausingActivities.size() > 0) {
+                    r = stack.mPausingActivities.get(stack.mPausingActivities.size()-1);
+                }
             }
             // Both of those null?  Fall back to 'this' again
             if (r == null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 6c11953..e8c8275 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -60,6 +60,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.UserId;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -226,7 +227,13 @@
      * When we are in the process of pausing an activity, before starting the
      * next one, this variable holds the activity that is currently being paused.
      */
-    ActivityRecord mPausingActivity = null;
+    final ArrayList<ActivityRecord> mPausingActivities = new ArrayList<ActivityRecord>();
+
+    /**
+     * These activities currently have their input paused, as they want for
+     * the next top activity to have its windows visible.
+     */
+    final ArrayList<ActivityRecord> mInputPausedActivities = new ArrayList<ActivityRecord>();
 
     /**
      * This is the last activity that we put into the paused state.  This is
@@ -274,13 +281,15 @@
     int mThumbnailWidth = -1;
     int mThumbnailHeight = -1;
 
-    static final int SLEEP_TIMEOUT_MSG = 8;
-    static final int PAUSE_TIMEOUT_MSG = 9;
-    static final int IDLE_TIMEOUT_MSG = 10;
-    static final int IDLE_NOW_MSG = 11;
-    static final int LAUNCH_TIMEOUT_MSG = 16;
-    static final int DESTROY_TIMEOUT_MSG = 17;
-    static final int RESUME_TOP_ACTIVITY_MSG = 19;
+    private int mCurrentUser;
+
+    static final int SLEEP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG;
+    static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
+    static final int IDLE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
+    static final int IDLE_NOW_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
+    static final int LAUNCH_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
+    static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
+    static final int RESUME_TOP_ACTIVITY_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
     
     final Handler mHandler = new Handler() {
         //public Handler() {
@@ -365,6 +374,7 @@
     }
     
     final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
+        // TODO: Don't look for any tasks from other users
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
@@ -377,6 +387,7 @@
     }
 
     final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
+        // TODO: Don't look for any tasks from other users
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
@@ -398,6 +409,7 @@
      * @return Returns the HistoryRecord of the next activity on the stack.
      */
     final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
+        // TODO: Don't look for any tasks from other users
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
@@ -444,10 +456,11 @@
 
         TaskRecord cp = null;
 
+        final int userId = UserId.getUserId(info.applicationInfo.uid);
         final int N = mHistory.size();
         for (int i=(N-1); i>=0; i--) {
             ActivityRecord r = mHistory.get(i);
-            if (!r.finishing && r.task != cp
+            if (!r.finishing && r.task != cp && r.userId == userId
                     && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
                 cp = r.task;
                 //Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
@@ -487,12 +500,13 @@
         if (info.targetActivity != null) {
             cls = new ComponentName(info.packageName, info.targetActivity);
         }
+        final int userId = UserId.getUserId(info.applicationInfo.uid);
 
         final int N = mHistory.size();
         for (int i=(N-1); i>=0; i--) {
             ActivityRecord r = mHistory.get(i);
             if (!r.finishing) {
-                if (r.intent.getComponent().equals(cls)) {
+                if (r.intent.getComponent().equals(cls) && r.userId == userId) {
                     //Slog.i(TAG, "Found matching class!");
                     //dump();
                     //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
@@ -511,6 +525,43 @@
         mService.mHandler.sendMessage(msg);
     }
 
+    /*
+     * Move the activities around in the stack to bring a user to the foreground.
+     * @return whether there are any activities for the specified user.
+     */
+    final boolean switchUser(int userId) {
+        synchronized (mService) {
+            mCurrentUser = userId;
+
+            // Only one activity? Nothing to do...
+            if (mHistory.size() < 2)
+                return false;
+
+            boolean haveActivities = false;
+            // Check if the top activity is from the new user.
+            ActivityRecord top = mHistory.get(mHistory.size() - 1);
+            if (top.userId == userId) return true;
+            // Otherwise, move the user's activities to the top.
+            int N = mHistory.size();
+            int i = 0;
+            while (i < N) {
+                ActivityRecord r = mHistory.get(i);
+                if (r.userId == userId) {
+                    ActivityRecord moveToTop = mHistory.remove(i);
+                    mHistory.add(moveToTop);
+                    // No need to check the top one now
+                    N--;
+                    haveActivities = true;
+                } else {
+                    i++;
+                }
+            }
+            // Transition from the old top to the new top
+            resumeTopActivityLocked(top);
+            return haveActivities;
+        }
+    }
+
     final boolean realStartActivityLocked(ActivityRecord r,
             ProcessRecord app, boolean andResume, boolean checkConfig)
             throws RemoteException {
@@ -710,7 +761,7 @@
         }
 
         mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
-                "activity", r.intent.getComponent(), false);
+                "activity", r.intent.getComponent(), false, false);
     }
     
     void stopIfSleepingLocked() {
@@ -762,9 +813,9 @@
                 startPausingLocked(false, true);
                 return;
             }
-            if (mPausingActivity != null) {
+            if (mPausingActivities.size() > 0) {
                 // Still waiting for something to pause; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
+                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivities);
                 return;
             }
 
@@ -827,11 +878,6 @@
     }
 
     private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
-        if (mPausingActivity != null) {
-            RuntimeException e = new RuntimeException();
-            Slog.e(TAG, "Trying to pause when pause is already pending for "
-                  + mPausingActivity, e);
-        }
         ActivityRecord prev = mResumedActivity;
         if (prev == null) {
             RuntimeException e = new RuntimeException();
@@ -839,19 +885,25 @@
             resumeTopActivityLocked(null);
             return;
         }
+        if (mPausingActivities.contains(prev)) {
+            RuntimeException e = new RuntimeException();
+            Slog.e(TAG, "Trying to pause when pause when already pausing " + prev, e);
+        }
         if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
         else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
         mResumedActivity = null;
-        mPausingActivity = prev;
+        mPausingActivities.add(prev);
         mLastPausedActivity = prev;
         prev.state = ActivityState.PAUSING;
         prev.task.touchActiveTime();
         prev.updateThumbnail(screenshotActivities(prev), null);
 
         mService.updateCpuStats();
+        ActivityRecord pausing;
         
         if (prev.app != null && prev.app.thread != null) {
             if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
+            pausing = prev;
             try {
                 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                         System.identityHashCode(prev),
@@ -864,12 +916,14 @@
             } catch (Exception e) {
                 // Ignore exception, if process died other code will cleanup.
                 Slog.w(TAG, "Exception thrown during pause", e);
-                mPausingActivity = null;
+                mPausingActivities.remove(prev);
                 mLastPausedActivity = null;
+                pausing = null;
             }
         } else {
-            mPausingActivity = null;
+            mPausingActivities.remove(prev);
             mLastPausedActivity = null;
+            pausing = null;
         }
 
         // If we are not going to sleep, we want to ensure the device is
@@ -883,18 +937,28 @@
             }
         }
 
-
-        if (mPausingActivity != null) {
+        if (pausing != null) {
             // Have the window manager pause its key dispatching until the new
             // activity has started.  If we're pausing the activity just because
             // the screen is being turned off and the UI is sleeping, don't interrupt
             // key dispatch; the same activity will pick it up again on wakeup.
             if (!uiSleeping) {
-                prev.pauseKeyDispatchingLocked();
+                pausing.pauseKeyDispatchingLocked();
+                mInputPausedActivities.add(prev);
             } else {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
             }
 
+            if (pausing.configDestroy) {
+                // The previous is being paused because the configuration
+                // is changing, which means it is actually stopping...
+                // To juggle the fact that we are also starting a new
+                // instance right now, we need to first completely stop
+                // the current instance before starting the new one.
+                if (DEBUG_PAUSE) Slog.v(TAG, "Destroying at pause: " + prev);
+                destroyActivityLocked(pausing, true, false, "pause-config");
+            }
+
             // Schedule a pause timeout in case the app doesn't respond.
             // We don't give it much time because this directly impacts the
             // responsiveness seen by the user.
@@ -906,7 +970,10 @@
             // This activity failed to schedule the
             // pause, so just treat it as being paused now.
             if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
-            resumeTopActivityLocked(null);
+        }
+
+        if (!mService.isSleeping()) {
+            resumeTopActivityLocked(pausing);
         }
     }
     
@@ -921,16 +988,17 @@
             if (index >= 0) {
                 r = mHistory.get(index);
                 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
-                if (mPausingActivity == r) {
+                if (mPausingActivities.contains(r)) {
                     if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
                             + (timeout ? " (due to timeout)" : " (pause complete)"));
                     r.state = ActivityState.PAUSED;
-                    completePauseLocked();
+                    completePauseLocked(r);
                 } else {
+                    ActivityRecord old = mPausingActivities.size() > 0
+                            ? mPausingActivities.get(0) : null;
                     EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
                             System.identityHashCode(r), r.shortComponentName, 
-                            mPausingActivity != null
-                                ? mPausingActivity.shortComponentName : "(none)");
+                            old != null ? old.shortComponentName : "(none)");
                 }
             }
         }
@@ -956,8 +1024,14 @@
                 ProcessRecord fgApp = null;
                 if (mResumedActivity != null) {
                     fgApp = mResumedActivity.app;
-                } else if (mPausingActivity != null) {
-                    fgApp = mPausingActivity.app;
+                } else {
+                    for (int i=mPausingActivities.size()-1; i>=0; i--) {
+                        ActivityRecord pausing = mPausingActivities.get(i);
+                        if (pausing.app == r.app) {
+                            fgApp = pausing.app;
+                            break;
+                        }
+                    }
                 }
                 if (r.app != null && fgApp != null && r.app != fgApp
                         && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
@@ -969,57 +1043,48 @@
         }
     }
 
-    private final void completePauseLocked() {
-        ActivityRecord prev = mPausingActivity;
+    private final void completePauseLocked(ActivityRecord prev) {
         if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
         
-        if (prev != null) {
-            if (prev.finishing) {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
-                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
-            } else if (prev.app != null) {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
-                if (prev.waitingVisible) {
-                    prev.waitingVisible = false;
-                    mWaitingVisibleActivities.remove(prev);
-                    if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
-                            TAG, "Complete pause, no longer waiting: " + prev);
-                }
-                if (prev.configDestroy) {
-                    // The previous is being paused because the configuration
-                    // is changing, which means it is actually stopping...
-                    // To juggle the fact that we are also starting a new
-                    // instance right now, we need to first completely stop
-                    // the current instance before starting the new one.
-                    if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
-                    destroyActivityLocked(prev, true, false, "pause-config");
-                } else {
-                    mStoppingActivities.add(prev);
-                    if (mStoppingActivities.size() > 3) {
-                        // If we already have a few activities waiting to stop,
-                        // then give up on things going idle and start clearing
-                        // them out.
-                        if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
-                        scheduleIdleLocked();
-                    } else {
-                        checkReadyForSleepLocked();
-                    }
-                }
-            } else {
-                if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
-                prev = null;
+        if (prev.finishing) {
+            if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
+            prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
+        } else if (prev.app != null) {
+            if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
+            if (prev.waitingVisible) {
+                prev.waitingVisible = false;
+                mWaitingVisibleActivities.remove(prev);
+                if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
+                        TAG, "Complete pause, no longer waiting: " + prev);
             }
-            mPausingActivity = null;
-        }
-
-        if (!mService.isSleeping()) {
-            resumeTopActivityLocked(prev);
+            if (prev.configDestroy) {
+                // The previous is being paused because the configuration
+                // is changing, which means it is actually stopping...
+                // To juggle the fact that we are also starting a new
+                // instance right now, we need to first completely stop
+                // the current instance before starting the new one.
+                if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
+                destroyActivityLocked(prev, true, false, "pause-config");
+            } else {
+                mStoppingActivities.add(prev);
+                if (mStoppingActivities.size() > 3) {
+                    // If we already have a few activities waiting to stop,
+                    // then give up on things going idle and start clearing
+                    // them out.
+                    if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
+                    scheduleIdleLocked();
+                } else {
+                    checkReadyForSleepLocked();
+                }
+            }
         } else {
-            checkReadyForSleepLocked();
+            if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
+            prev = null;
         }
-        
-        if (prev != null) {
-            prev.resumeKeyDispatchingLocked();
+        mPausingActivities.remove(prev);
+
+        if (mService.isSleeping()) {
+            checkReadyForSleepLocked();
         }
 
         if (prev.app != null && prev.cpuTimeAtResume > 0
@@ -1077,7 +1142,9 @@
         if (mMainStack) {
             mService.setFocusedActivityLocked(next);
         }
-        next.resumeKeyDispatchingLocked();
+        if (mInputPausedActivities.remove(next)) {
+            next.resumeKeyDispatchingLocked();
+        }
         ensureActivitiesVisibleLocked(null, 0);
         mService.mWindowManager.executeAppTransition();
         mNoAnimActivities.clear();
@@ -1272,7 +1339,7 @@
             // There are no more activities!  Let's just start up the
             // Launcher...
             if (mMainStack) {
-                return mService.startHomeActivityLocked();
+                return mService.startHomeActivityLocked(0);
             }
         }
 
@@ -1307,13 +1374,6 @@
 
         if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
 
-        // If we are currently pausing an activity, then don't do anything
-        // until that is done.
-        if (mPausingActivity != null) {
-            if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
-            return false;
-        }
-
         // Okay we are now going to start a switch, to 'next'.  We may first
         // have to pause the current activity, but this is an important point
         // where we have decided to go to 'next' so keep track of that.
@@ -1384,6 +1444,7 @@
         // Launching this app's activity, make sure the app is no longer
         // considered stopped.
         try {
+            // TODO: Apply to the correct userId
             AppGlobals.getPackageManager().setPackageStoppedState(
                     next.packageName, false);
         } catch (RemoteException e1) {
@@ -2354,7 +2415,7 @@
                 }
             }
         }
-        
+
         ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,
                 intent, resolvedType, aInfo, mService.mConfiguration,
                 resultRecord, resultWho, requestCode, componentSpecified);
@@ -2394,7 +2455,7 @@
         
         err = startActivityUncheckedLocked(r, sourceRecord,
                 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
-        if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
+        if (mDismissKeyguardOnNextActivity && mPausingActivities.size() == 0) {
             // Someone asked to have the keyguard dismissed on the next
             // activity start, but we are not actually doing an activity
             // switch...  just dismiss the keyguard now, because we
@@ -2420,7 +2481,8 @@
             int grantedMode, boolean onlyIfNeeded, boolean doResume) {
         final Intent intent = r.intent;
         final int callingUid = r.launchedFromUid;
-        
+        final int userId = r.userId;
+
         int launchFlags = intent.getFlags();
         
         // We'll invoke onUserLeaving before onPause only if the launching
@@ -2648,7 +2710,7 @@
             // once.
             ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
             if (top != null && r.resultTo == null) {
-                if (top.realActivity.equals(r.realActivity)) {
+                if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                     if (top.app != null && top.app.thread != null) {
                         if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                             || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
@@ -2821,12 +2883,12 @@
             int grantedMode, IBinder resultTo,
             String resultWho, int requestCode, boolean onlyIfNeeded,
             boolean debug, String profileFile, ParcelFileDescriptor profileFd,
-            boolean autoStopProfiler, WaitResult outResult, Configuration config) {
+            boolean autoStopProfiler,
+            WaitResult outResult, Configuration config, int userId) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
-
         boolean componentSpecified = intent.getComponent() != null;
 
         // Don't modify the client's object!
@@ -2835,6 +2897,7 @@
         // Collect information about the target of the Intent.
         ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug,
                 profileFile, profileFd, autoStopProfiler);
+        aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
         synchronized (mService) {
             int callingPid;
@@ -2915,6 +2978,7 @@
                                         PackageManager.MATCH_DEFAULT_ONLY
                                         | ActivityManagerService.STOCK_PM_FLAGS);
                             aInfo = rInfo != null ? rInfo.activityInfo : null;
+                            aInfo = mService.getActivityInfoForUser(aInfo, userId);
                         } catch (RemoteException e) {
                             aInfo = null;
                         }
@@ -2977,7 +3041,8 @@
     }
     
     final int startActivities(IApplicationThread caller, int callingUid,
-            Intent[] intents, String[] resolvedTypes, IBinder resultTo) {
+            Intent[] intents,
+            String[] resolvedTypes, IBinder resultTo, int userId) {
         if (intents == null) {
             throw new NullPointerException("intents is null");
         }
@@ -3022,6 +3087,8 @@
                     // Collect information about the target of the Intent.
                     ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false,
                             null, null, false);
+                    // TODO: New, check if this is correct
+                    aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
                     if (mMainStack && aInfo != null && (aInfo.applicationInfo.flags
                             & ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
@@ -3059,7 +3126,18 @@
         }
         mService.notifyAll();
     }
-    
+
+    void reportActivityDrawnLocked(ActivityRecord r) {
+        if (mResumedActivity == r) {
+            // Once the resumed activity has been drawn, we can stop
+            // pausing input on all other activities.
+            for (int i=mInputPausedActivities.size()-1; i>=0; i--) {
+                mInputPausedActivities.get(i).resumeKeyDispatchingLocked();
+            }
+            mInputPausedActivities.clear();
+        }
+    }
+
     void reportActivityVisibleLocked(ActivityRecord r) {
         for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
             WaitResult w = mWaitingActivityVisible.get(i);
@@ -3118,7 +3196,9 @@
                     mService.setFocusedActivityLocked(topRunningActivityLocked(null));
                 }
             }
-            r.resumeKeyDispatchingLocked();
+            if (mInputPausedActivities.remove(r)) {
+                r.resumeKeyDispatchingLocked();
+            }
             try {
                 r.stopped = false;
                 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
@@ -3444,7 +3524,7 @@
             // Tell window manager to prepare for this one to be removed.
             mService.mWindowManager.setAppVisibility(r.appToken, false);
                 
-            if (mPausingActivity == null) {
+            if (!mPausingActivities.contains(r)) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
                 if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
                 startPausingLocked(false, false);
@@ -3528,6 +3608,20 @@
         return r;
     }
 
+    final void appDiedLocked(ProcessRecord app) {
+        for (int i=mPausingActivities.size()-1; i>=0; i--) {
+            ActivityRecord r = mPausingActivities.get(i);
+            if (r.app == app) {
+                if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + r);
+                mPausingActivities.remove(i);
+                mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+            }
+        }
+        if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
+            mLastPausedActivity = null;
+        }
+    }
+
     /**
      * Perform the common clean-up of an activity record.  This is called both
      * as part of destroyActivityLocked() (when destroying the client-side
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
new file mode 100644
index 0000000..39b63db
--- /dev/null
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.IIntentReceiver;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserId;
+import android.util.EventLog;
+import android.util.Slog;
+
+/**
+ * BROADCASTS
+ *
+ * We keep two broadcast queues and associated bookkeeping, one for those at
+ * foreground priority, and one for normal (background-priority) broadcasts.
+ */
+public class BroadcastQueue {
+    static final String TAG = "BroadcastQueue";
+    static final String TAG_MU = ActivityManagerService.TAG_MU;
+    static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST;
+    static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
+    static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
+
+    static final int MAX_BROADCAST_HISTORY = 25;
+
+    final ActivityManagerService mService;
+
+    /**
+     * Recognizable moniker for this queue
+     */
+    final String mQueueName;
+
+    /**
+     * Timeout period for this queue's broadcasts
+     */
+    final long mTimeoutPeriod;
+
+    /**
+     * Lists of all active broadcasts that are to be executed immediately
+     * (without waiting for another broadcast to finish).  Currently this only
+     * contains broadcasts to registered receivers, to avoid spinning up
+     * a bunch of processes to execute IntentReceiver components.  Background-
+     * and foreground-priority broadcasts are queued separately.
+     */
+    final ArrayList<BroadcastRecord> mParallelBroadcasts
+            = new ArrayList<BroadcastRecord>();
+    /**
+     * List of all active broadcasts that are to be executed one at a time.
+     * The object at the top of the list is the currently activity broadcasts;
+     * those after it are waiting for the top to finish.  As with parallel
+     * broadcasts, separate background- and foreground-priority queues are
+     * maintained.
+     */
+    final ArrayList<BroadcastRecord> mOrderedBroadcasts
+            = new ArrayList<BroadcastRecord>();
+
+    /**
+     * Historical data of past broadcasts, for debugging.
+     */
+    final BroadcastRecord[] mBroadcastHistory
+            = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+
+    /**
+     * Set when we current have a BROADCAST_INTENT_MSG in flight.
+     */
+    boolean mBroadcastsScheduled = false;
+
+    /**
+     * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
+     */
+    boolean mPendingBroadcastTimeoutMessage;
+
+    /**
+     * Intent broadcasts that we have tried to start, but are
+     * waiting for the application's process to be created.  We only
+     * need one per scheduling class (instead of a list) because we always
+     * process broadcasts one at a time, so no others can be started while
+     * waiting for this one.
+     */
+    BroadcastRecord mPendingBroadcast = null;
+
+    /**
+     * The receiver index that is pending, to restart the broadcast if needed.
+     */
+    int mPendingBroadcastRecvIndex;
+
+    static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG;
+    static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
+
+    final Handler mHandler = new Handler() {
+        //public Handler() {
+        //    if (localLOGV) Slog.v(TAG, "Handler started!");
+        //}
+
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case BROADCAST_INTENT_MSG: {
+                    if (DEBUG_BROADCAST) Slog.v(
+                            TAG, "Received BROADCAST_INTENT_MSG");
+                    processNextBroadcast(true);
+                } break;
+                case BROADCAST_TIMEOUT_MSG: {
+                    synchronized (mService) {
+                        broadcastTimeoutLocked(true);
+                    }
+                } break;
+            }
+        }
+    };
+
+    private final class AppNotResponding implements Runnable {
+        private final ProcessRecord mApp;
+        private final String mAnnotation;
+
+        public AppNotResponding(ProcessRecord app, String annotation) {
+            mApp = app;
+            mAnnotation = annotation;
+        }
+
+        @Override
+        public void run() {
+            mService.appNotResponding(mApp, null, null, mAnnotation);
+        }
+    }
+
+    BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) {
+        mService = service;
+        mQueueName = name;
+        mTimeoutPeriod = timeoutPeriod;
+    }
+
+    public boolean isPendingBroadcastProcessLocked(int pid) {
+        return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
+    }
+
+    public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
+        mParallelBroadcasts.add(r);
+    }
+
+    public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
+        mOrderedBroadcasts.add(r);
+    }
+
+    public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
+        for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+            if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
+                if (DEBUG_BROADCAST) Slog.v(TAG,
+                        "***** DROPPING PARALLEL ["
+                + mQueueName + "]: " + r.intent);
+                mParallelBroadcasts.set(i, r);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
+        for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
+            if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
+                if (DEBUG_BROADCAST) Slog.v(TAG,
+                        "***** DROPPING ORDERED ["
+                        + mQueueName + "]: " + r.intent);
+                mOrderedBroadcasts.set(i, r);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private final void processCurBroadcastLocked(BroadcastRecord r,
+            ProcessRecord app) throws RemoteException {
+        if (DEBUG_BROADCAST)  Slog.v(TAG,
+                "Process cur broadcast " + r + " for app " + app);
+        if (app.thread == null) {
+            throw new RemoteException();
+        }
+        r.receiver = app.thread.asBinder();
+        r.curApp = app;
+        app.curReceiver = r;
+        mService.updateLruProcessLocked(app, true, true);
+
+        // Tell the application to launch this receiver.
+        r.intent.setComponent(r.curComponent);
+
+        boolean started = false;
+        try {
+            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
+                    "Delivering to component " + r.curComponent
+                    + ": " + r);
+            mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
+            app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
+                    mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
+                    r.resultCode, r.resultData, r.resultExtras, r.ordered);
+            if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    "Process cur broadcast " + r + " DELIVERED for app " + app);
+            started = true;
+        } finally {
+            if (!started) {
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Process cur broadcast " + r + ": NOT STARTED!");
+                r.receiver = null;
+                r.curApp = null;
+                app.curReceiver = null;
+            }
+        }
+    }
+
+    public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
+        boolean didSomething = false;
+        final BroadcastRecord br = mPendingBroadcast;
+        if (br != null && br.curApp.pid == app.pid) {
+            try {
+                mPendingBroadcast = null;
+                processCurBroadcastLocked(br, app);
+                didSomething = true;
+            } catch (Exception e) {
+                Slog.w(TAG, "Exception in new application when starting receiver "
+                        + br.curComponent.flattenToShortString(), e);
+                logBroadcastReceiverDiscardLocked(br);
+                finishReceiverLocked(br, br.resultCode, br.resultData,
+                        br.resultExtras, br.resultAbort, true);
+                scheduleBroadcastsLocked();
+                // We need to reset the state if we fails to start the receiver.
+                br.state = BroadcastRecord.IDLE;
+                throw new RuntimeException(e.getMessage());
+            }
+        }
+        return didSomething;
+    }
+
+    public void skipPendingBroadcastLocked(int pid) {
+        final BroadcastRecord br = mPendingBroadcast;
+        if (br != null && br.curApp.pid == pid) {
+            br.state = BroadcastRecord.IDLE;
+            br.nextReceiver = mPendingBroadcastRecvIndex;
+            mPendingBroadcast = null;
+            scheduleBroadcastsLocked();
+        }
+    }
+
+    public void skipCurrentReceiverLocked(ProcessRecord app) {
+        boolean reschedule = false;
+        BroadcastRecord r = app.curReceiver;
+        if (r != null) {
+            // The current broadcast is waiting for this app's receiver
+            // to be finished.  Looks like that's not going to happen, so
+            // let the broadcast continue.
+            logBroadcastReceiverDiscardLocked(r);
+            finishReceiverLocked(r, r.resultCode, r.resultData,
+                    r.resultExtras, r.resultAbort, true);
+            reschedule = true;
+        }
+
+        r = mPendingBroadcast;
+        if (r != null && r.curApp == app) {
+            if (DEBUG_BROADCAST) Slog.v(TAG,
+                    "[" + mQueueName + "] skip & discard pending app " + r);
+            logBroadcastReceiverDiscardLocked(r);
+            finishReceiverLocked(r, r.resultCode, r.resultData,
+                    r.resultExtras, r.resultAbort, true);
+            reschedule = true;
+        }
+        if (reschedule) {
+            scheduleBroadcastsLocked();
+        }
+    }
+
+    public void scheduleBroadcastsLocked() {
+        if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+                + mQueueName + "]: current="
+                + mBroadcastsScheduled);
+
+        if (mBroadcastsScheduled) {
+            return;
+        }
+        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
+        mBroadcastsScheduled = true;
+    }
+
+    public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
+        if (mOrderedBroadcasts.size() > 0) {
+            final BroadcastRecord r = mOrderedBroadcasts.get(0);
+            if (r != null && r.receiver == receiver) {
+                return r;
+            }
+        }
+        return null;
+    }
+
+    public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
+            String resultData, Bundle resultExtras, boolean resultAbort,
+            boolean explicit) {
+        int state = r.state;
+        r.state = BroadcastRecord.IDLE;
+        if (state == BroadcastRecord.IDLE) {
+            if (explicit) {
+                Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
+            }
+        }
+        r.receiver = null;
+        r.intent.setComponent(null);
+        if (r.curApp != null) {
+            r.curApp.curReceiver = null;
+        }
+        if (r.curFilter != null) {
+            r.curFilter.receiverList.curBroadcast = null;
+        }
+        r.curFilter = null;
+        r.curApp = null;
+        r.curComponent = null;
+        r.curReceiver = null;
+        mPendingBroadcast = null;
+
+        r.resultCode = resultCode;
+        r.resultData = resultData;
+        r.resultExtras = resultExtras;
+        r.resultAbort = resultAbort;
+
+        // We will process the next receiver right now if this is finishing
+        // an app receiver (which is always asynchronous) or after we have
+        // come back from calling a receiver.
+        return state == BroadcastRecord.APP_RECEIVE
+                || state == BroadcastRecord.CALL_DONE_RECEIVE;
+    }
+
+    private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
+            Intent intent, int resultCode, String data, Bundle extras,
+            boolean ordered, boolean sticky) throws RemoteException {
+        // Send the intent to the receiver asynchronously using one-way binder calls.
+        if (app != null && app.thread != null) {
+            // If we have an app thread, do the call through that so it is
+            // correctly ordered with other one-way calls.
+            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
+                    data, extras, ordered, sticky);
+        } else {
+            receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
+        }
+    }
+
+    private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
+            BroadcastFilter filter, boolean ordered) {
+        boolean skip = false;
+        if (filter.requiredPermission != null) {
+            int perm = mService.checkComponentPermission(filter.requiredPermission,
+                    r.callingPid, r.callingUid, -1, true);
+            if (perm != PackageManager.PERMISSION_GRANTED) {
+                Slog.w(TAG, "Permission Denial: broadcasting "
+                        + r.intent.toString()
+                        + " from " + r.callerPackage + " (pid="
+                        + r.callingPid + ", uid=" + r.callingUid + ")"
+                        + " requires " + filter.requiredPermission
+                        + " due to registered receiver " + filter);
+                skip = true;
+            }
+        }
+        if (r.requiredPermission != null) {
+            int perm = mService.checkComponentPermission(r.requiredPermission,
+                    filter.receiverList.pid, filter.receiverList.uid, -1, true);
+            if (perm != PackageManager.PERMISSION_GRANTED) {
+                Slog.w(TAG, "Permission Denial: receiving "
+                        + r.intent.toString()
+                        + " to " + filter.receiverList.app
+                        + " (pid=" + filter.receiverList.pid
+                        + ", uid=" + filter.receiverList.uid + ")"
+                        + " requires " + r.requiredPermission
+                        + " due to sender " + r.callerPackage
+                        + " (uid " + r.callingUid + ")");
+                skip = true;
+            }
+        }
+
+        if (!skip) {
+            // If this is not being sent as an ordered broadcast, then we
+            // don't want to touch the fields that keep track of the current
+            // state of ordered broadcasts.
+            if (ordered) {
+                r.receiver = filter.receiverList.receiver.asBinder();
+                r.curFilter = filter;
+                filter.receiverList.curBroadcast = r;
+                r.state = BroadcastRecord.CALL_IN_RECEIVE;
+                if (filter.receiverList.app != null) {
+                    // Bump hosting application to no longer be in background
+                    // scheduling class.  Note that we can't do that if there
+                    // isn't an app...  but we can only be in that case for
+                    // things that directly call the IActivityManager API, which
+                    // are already core system stuff so don't matter for this.
+                    r.curApp = filter.receiverList.app;
+                    filter.receiverList.app.curReceiver = r;
+                    mService.updateOomAdjLocked();
+                }
+            }
+            try {
+                if (DEBUG_BROADCAST_LIGHT) {
+                    int seq = r.intent.getIntExtra("seq", -1);
+                    Slog.i(TAG, "Delivering to " + filter
+                            + " (seq=" + seq + "): " + r);
+                }
+                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
+                    new Intent(r.intent), r.resultCode,
+                    r.resultData, r.resultExtras, r.ordered, r.initialSticky);
+                if (ordered) {
+                    r.state = BroadcastRecord.CALL_DONE_RECEIVE;
+                }
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
+                if (ordered) {
+                    r.receiver = null;
+                    r.curFilter = null;
+                    filter.receiverList.curBroadcast = null;
+                    if (filter.receiverList.app != null) {
+                        filter.receiverList.app.curReceiver = null;
+                    }
+                }
+            }
+        }
+    }
+
+    final void processNextBroadcast(boolean fromMsg) {
+        synchronized(mService) {
+            BroadcastRecord r;
+
+            if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
+                    + mQueueName + "]: "
+                    + mParallelBroadcasts.size() + " broadcasts, "
+                    + mOrderedBroadcasts.size() + " ordered broadcasts");
+
+            mService.updateCpuStats();
+
+            if (fromMsg) {
+                mBroadcastsScheduled = false;
+            }
+
+            // First, deliver any non-serialized broadcasts right away.
+            while (mParallelBroadcasts.size() > 0) {
+                r = mParallelBroadcasts.remove(0);
+                r.dispatchTime = SystemClock.uptimeMillis();
+                r.dispatchClockTime = System.currentTimeMillis();
+                final int N = r.receivers.size();
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+                        + mQueueName + "] " + r);
+                for (int i=0; i<N; i++) {
+                    Object target = r.receivers.get(i);
+                    if (DEBUG_BROADCAST)  Slog.v(TAG,
+                            "Delivering non-ordered on [" + mQueueName + "] to registered "
+                            + target + ": " + r);
+                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
+                }
+                addBroadcastToHistoryLocked(r);
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+                        + mQueueName + "] " + r);
+            }
+
+            // Now take care of the next serialized one...
+
+            // If we are waiting for a process to come up to handle the next
+            // broadcast, then do nothing at this point.  Just in case, we
+            // check that the process we're waiting for still exists.
+            if (mPendingBroadcast != null) {
+                if (DEBUG_BROADCAST_LIGHT) {
+                    Slog.v(TAG, "processNextBroadcast ["
+                            + mQueueName + "]: waiting for "
+                            + mPendingBroadcast.curApp);
+                }
+
+                boolean isDead;
+                synchronized (mService.mPidsSelfLocked) {
+                    isDead = (mService.mPidsSelfLocked.get(
+                            mPendingBroadcast.curApp.pid) == null);
+                }
+                if (!isDead) {
+                    // It's still alive, so keep waiting
+                    return;
+                } else {
+                    Slog.w(TAG, "pending app  ["
+                            + mQueueName + "]" + mPendingBroadcast.curApp
+                            + " died before responding to broadcast");
+                    mPendingBroadcast.state = BroadcastRecord.IDLE;
+                    mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
+                    mPendingBroadcast = null;
+                }
+            }
+
+            boolean looped = false;
+            
+            do {
+                if (mOrderedBroadcasts.size() == 0) {
+                    // No more broadcasts pending, so all done!
+                    mService.scheduleAppGcsLocked();
+                    if (looped) {
+                        // If we had finished the last ordered broadcast, then
+                        // make sure all processes have correct oom and sched
+                        // adjustments.
+                        mService.updateOomAdjLocked();
+                    }
+                    return;
+                }
+                r = mOrderedBroadcasts.get(0);
+                boolean forceReceive = false;
+
+                // Ensure that even if something goes awry with the timeout
+                // detection, we catch "hung" broadcasts here, discard them,
+                // and continue to make progress.
+                //
+                // This is only done if the system is ready so that PRE_BOOT_COMPLETED
+                // receivers don't get executed with timeouts. They're intended for
+                // one time heavy lifting after system upgrades and can take
+                // significant amounts of time.
+                int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
+                if (mService.mProcessesReady && r.dispatchTime > 0) {
+                    long now = SystemClock.uptimeMillis();
+                    if ((numReceivers > 0) &&
+                            (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
+                        Slog.w(TAG, "Hung broadcast ["
+                                + mQueueName + "] discarded after timeout failure:"
+                                + " now=" + now
+                                + " dispatchTime=" + r.dispatchTime
+                                + " startTime=" + r.receiverTime
+                                + " intent=" + r.intent
+                                + " numReceivers=" + numReceivers
+                                + " nextReceiver=" + r.nextReceiver
+                                + " state=" + r.state);
+                        broadcastTimeoutLocked(false); // forcibly finish this broadcast
+                        forceReceive = true;
+                        r.state = BroadcastRecord.IDLE;
+                    }
+                }
+
+                if (r.state != BroadcastRecord.IDLE) {
+                    if (DEBUG_BROADCAST) Slog.d(TAG,
+                            "processNextBroadcast("
+                            + mQueueName + ") called when not idle (state="
+                            + r.state + ")");
+                    return;
+                }
+
+                if (r.receivers == null || r.nextReceiver >= numReceivers
+                        || r.resultAbort || forceReceive) {
+                    // No more receivers for this broadcast!  Send the final
+                    // result if requested...
+                    if (r.resultTo != null) {
+                        try {
+                            if (DEBUG_BROADCAST) {
+                                int seq = r.intent.getIntExtra("seq", -1);
+                                Slog.i(TAG, "Finishing broadcast ["
+                                        + mQueueName + "] " + r.intent.getAction()
+                                        + " seq=" + seq + " app=" + r.callerApp);
+                            }
+                            performReceiveLocked(r.callerApp, r.resultTo,
+                                new Intent(r.intent), r.resultCode,
+                                r.resultData, r.resultExtras, false, false);
+                            // Set this to null so that the reference
+                            // (local and remote) isnt kept in the mBroadcastHistory.
+                            r.resultTo = null;
+                        } catch (RemoteException e) {
+                            Slog.w(TAG, "Failure ["
+                                    + mQueueName + "] sending broadcast result of "
+                                    + r.intent, e);
+                        }
+                    }
+
+                    if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+                    cancelBroadcastTimeoutLocked();
+
+                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
+                            + r);
+
+                    // ... and on to the next...
+                    addBroadcastToHistoryLocked(r);
+                    mOrderedBroadcasts.remove(0);
+                    r = null;
+                    looped = true;
+                    continue;
+                }
+            } while (r == null);
+
+            // Get the next receiver...
+            int recIdx = r.nextReceiver++;
+
+            // Keep track of when this receiver started, and make sure there
+            // is a timeout message pending to kill it if need be.
+            r.receiverTime = SystemClock.uptimeMillis();
+            if (recIdx == 0) {
+                r.dispatchTime = r.receiverTime;
+                r.dispatchClockTime = System.currentTimeMillis();
+                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
+                        + mQueueName + "] " + r);
+            }
+            if (! mPendingBroadcastTimeoutMessage) {
+                long timeoutTime = r.receiverTime + mTimeoutPeriod;
+                if (DEBUG_BROADCAST) Slog.v(TAG,
+                        "Submitting BROADCAST_TIMEOUT_MSG ["
+                        + mQueueName + "] for " + r + " at " + timeoutTime);
+                setBroadcastTimeoutLocked(timeoutTime);
+            }
+
+            Object nextReceiver = r.receivers.get(recIdx);
+            if (nextReceiver instanceof BroadcastFilter) {
+                // Simple case: this is a registered receiver who gets
+                // a direct call.
+                BroadcastFilter filter = (BroadcastFilter)nextReceiver;
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Delivering ordered ["
+                        + mQueueName + "] to registered "
+                        + filter + ": " + r);
+                deliverToRegisteredReceiverLocked(r, filter, r.ordered);
+                if (r.receiver == null || !r.ordered) {
+                    // The receiver has already finished, so schedule to
+                    // process the next one.
+                    if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
+                            + mQueueName + "]: ordered="
+                            + r.ordered + " receiver=" + r.receiver);
+                    r.state = BroadcastRecord.IDLE;
+                    scheduleBroadcastsLocked();
+                }
+                return;
+            }
+
+            // Hard case: need to instantiate the receiver, possibly
+            // starting its application process to host it.
+
+            ResolveInfo info =
+                (ResolveInfo)nextReceiver;
+
+            boolean skip = false;
+            int perm = mService.checkComponentPermission(info.activityInfo.permission,
+                    r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
+                    info.activityInfo.exported);
+            if (perm != PackageManager.PERMISSION_GRANTED) {
+                if (!info.activityInfo.exported) {
+                    Slog.w(TAG, "Permission Denial: broadcasting "
+                            + r.intent.toString()
+                            + " from " + r.callerPackage + " (pid=" + r.callingPid
+                            + ", uid=" + r.callingUid + ")"
+                            + " is not exported from uid " + info.activityInfo.applicationInfo.uid
+                            + " due to receiver " + info.activityInfo.packageName
+                            + "/" + info.activityInfo.name);
+                } else {
+                    Slog.w(TAG, "Permission Denial: broadcasting "
+                            + r.intent.toString()
+                            + " from " + r.callerPackage + " (pid=" + r.callingPid
+                            + ", uid=" + r.callingUid + ")"
+                            + " requires " + info.activityInfo.permission
+                            + " due to receiver " + info.activityInfo.packageName
+                            + "/" + info.activityInfo.name);
+                }
+                skip = true;
+            }
+            if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
+                r.requiredPermission != null) {
+                try {
+                    perm = AppGlobals.getPackageManager().
+                            checkPermission(r.requiredPermission,
+                                    info.activityInfo.applicationInfo.packageName);
+                } catch (RemoteException e) {
+                    perm = PackageManager.PERMISSION_DENIED;
+                }
+                if (perm != PackageManager.PERMISSION_GRANTED) {
+                    Slog.w(TAG, "Permission Denial: receiving "
+                            + r.intent + " to "
+                            + info.activityInfo.applicationInfo.packageName
+                            + " requires " + r.requiredPermission
+                            + " due to sender " + r.callerPackage
+                            + " (uid " + r.callingUid + ")");
+                    skip = true;
+                }
+            }
+            if (r.curApp != null && r.curApp.crashing) {
+                // If the target process is crashing, just skip it.
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Skipping deliver ordered ["
+                        + mQueueName + "] " + r + " to " + r.curApp
+                        + ": process crashing");
+                skip = true;
+            }
+
+            if (skip) {
+                if (DEBUG_BROADCAST)  Slog.v(TAG,
+                        "Skipping delivery of ordered ["
+                        + mQueueName + "] " + r + " for whatever reason");
+                r.receiver = null;
+                r.curFilter = null;
+                r.state = BroadcastRecord.IDLE;
+                scheduleBroadcastsLocked();
+                return;
+            }
+
+            r.state = BroadcastRecord.APP_RECEIVE;
+            String targetProcess = info.activityInfo.processName;
+            r.curComponent = new ComponentName(
+                    info.activityInfo.applicationInfo.packageName,
+                    info.activityInfo.name);
+            if (r.callingUid != Process.SYSTEM_UID) {
+                info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, UserId
+                        .getUserId(r.callingUid));
+            }
+            r.curReceiver = info.activityInfo;
+            if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
+                Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
+                        + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
+                        + info.activityInfo.applicationInfo.uid);
+            }
+
+            // Broadcast is being executed, its package can't be stopped.
+            try {
+                AppGlobals.getPackageManager().setPackageStoppedState(
+                        r.curComponent.getPackageName(), false);
+            } catch (RemoteException e) {
+            } catch (IllegalArgumentException e) {
+                Slog.w(TAG, "Failed trying to unstop package "
+                        + r.curComponent.getPackageName() + ": " + e);
+            }
+
+            // Is this receiver's application already running?
+            ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
+                    info.activityInfo.applicationInfo.uid);
+            if (app != null && app.thread != null) {
+                try {
+                    app.addPackage(info.activityInfo.packageName);
+                    processCurBroadcastLocked(r, app);
+                    return;
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Exception when sending broadcast to "
+                          + r.curComponent, e);
+                }
+
+                // If a dead object exception was thrown -- fall through to
+                // restart the application.
+            }
+
+            // Not running -- get it started, to be executed when the app comes up.
+            if (DEBUG_BROADCAST)  Slog.v(TAG,
+                    "Need to start app ["
+                    + mQueueName + "] " + targetProcess + " for broadcast " + r);
+            if ((r.curApp=mService.startProcessLocked(targetProcess,
+                    info.activityInfo.applicationInfo, true,
+                    r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
+                    "broadcast", r.curComponent,
+                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))
+                            == null) {
+                // Ah, this recipient is unavailable.  Finish it if necessary,
+                // and mark the broadcast record as ready for the next.
+                Slog.w(TAG, "Unable to launch app "
+                        + info.activityInfo.applicationInfo.packageName + "/"
+                        + info.activityInfo.applicationInfo.uid + " for broadcast "
+                        + r.intent + ": process is bad");
+                logBroadcastReceiverDiscardLocked(r);
+                finishReceiverLocked(r, r.resultCode, r.resultData,
+                        r.resultExtras, r.resultAbort, true);
+                scheduleBroadcastsLocked();
+                r.state = BroadcastRecord.IDLE;
+                return;
+            }
+
+            mPendingBroadcast = r;
+            mPendingBroadcastRecvIndex = recIdx;
+        }
+    }
+
+    final void setBroadcastTimeoutLocked(long timeoutTime) {
+        if (! mPendingBroadcastTimeoutMessage) {
+            Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
+            mHandler.sendMessageAtTime(msg, timeoutTime);
+            mPendingBroadcastTimeoutMessage = true;
+        }
+    }
+
+    final void cancelBroadcastTimeoutLocked() {
+        if (mPendingBroadcastTimeoutMessage) {
+            mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
+            mPendingBroadcastTimeoutMessage = false;
+        }
+    }
+
+    final void broadcastTimeoutLocked(boolean fromMsg) {
+        if (fromMsg) {
+            mPendingBroadcastTimeoutMessage = false;
+        }
+
+        if (mOrderedBroadcasts.size() == 0) {
+            return;
+        }
+
+        long now = SystemClock.uptimeMillis();
+        BroadcastRecord r = mOrderedBroadcasts.get(0);
+        if (fromMsg) {
+            if (mService.mDidDexOpt) {
+                // Delay timeouts until dexopt finishes.
+                mService.mDidDexOpt = false;
+                long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
+                setBroadcastTimeoutLocked(timeoutTime);
+                return;
+            }
+            if (!mService.mProcessesReady) {
+                // Only process broadcast timeouts if the system is ready. That way
+                // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
+                // to do heavy lifting for system up.
+                return;
+            }
+
+            long timeoutTime = r.receiverTime + mTimeoutPeriod;
+            if (timeoutTime > now) {
+                // We can observe premature timeouts because we do not cancel and reset the
+                // broadcast timeout message after each receiver finishes.  Instead, we set up
+                // an initial timeout then kick it down the road a little further as needed
+                // when it expires.
+                if (DEBUG_BROADCAST) Slog.v(TAG,
+                        "Premature timeout ["
+                        + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+                        + timeoutTime);
+                setBroadcastTimeoutLocked(timeoutTime);
+                return;
+            }
+        }
+
+        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+                + ", started " + (now - r.receiverTime) + "ms ago");
+        r.receiverTime = now;
+        r.anrCount++;
+
+        // Current receiver has passed its expiration date.
+        if (r.nextReceiver <= 0) {
+            Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
+            return;
+        }
+
+        ProcessRecord app = null;
+        String anrMessage = null;
+
+        Object curReceiver = r.receivers.get(r.nextReceiver-1);
+        Slog.w(TAG, "Receiver during timeout: " + curReceiver);
+        logBroadcastReceiverDiscardLocked(r);
+        if (curReceiver instanceof BroadcastFilter) {
+            BroadcastFilter bf = (BroadcastFilter)curReceiver;
+            if (bf.receiverList.pid != 0
+                    && bf.receiverList.pid != ActivityManagerService.MY_PID) {
+                synchronized (mService.mPidsSelfLocked) {
+                    app = mService.mPidsSelfLocked.get(
+                            bf.receiverList.pid);
+                }
+            }
+        } else {
+            app = r.curApp;
+        }
+
+        if (app != null) {
+            anrMessage = "Broadcast of " + r.intent.toString();
+        }
+
+        if (mPendingBroadcast == r) {
+            mPendingBroadcast = null;
+        }
+
+        // Move on to the next receiver.
+        finishReceiverLocked(r, r.resultCode, r.resultData,
+                r.resultExtras, r.resultAbort, true);
+        scheduleBroadcastsLocked();
+
+        if (anrMessage != null) {
+            // Post the ANR to the handler since we do not want to process ANRs while
+            // potentially holding our lock.
+            mHandler.post(new AppNotResponding(app, anrMessage));
+        }
+    }
+
+    private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
+        if (r.callingUid < 0) {
+            // This was from a registerReceiver() call; ignore it.
+            return;
+        }
+        System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
+                MAX_BROADCAST_HISTORY-1);
+        r.finishTime = SystemClock.uptimeMillis();
+        mBroadcastHistory[0] = r;
+    }
+
+    final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
+        if (r.nextReceiver > 0) {
+            Object curReceiver = r.receivers.get(r.nextReceiver-1);
+            if (curReceiver instanceof BroadcastFilter) {
+                BroadcastFilter bf = (BroadcastFilter) curReceiver;
+                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
+                        System.identityHashCode(r),
+                        r.intent.getAction(),
+                        r.nextReceiver - 1,
+                        System.identityHashCode(bf));
+            } else {
+                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+                        System.identityHashCode(r),
+                        r.intent.getAction(),
+                        r.nextReceiver - 1,
+                        ((ResolveInfo)curReceiver).toString());
+            }
+        } else {
+            Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
+                    + r);
+            EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+                    System.identityHashCode(r),
+                    r.intent.getAction(),
+                    r.nextReceiver,
+                    "NONE");
+        }
+    }
+
+    final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+            int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
+        if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
+                || mPendingBroadcast != null) {
+            boolean printed = false;
+            for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+                BroadcastRecord br = mParallelBroadcasts.get(i);
+                if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+                    continue;
+                }
+                if (!printed) {
+                    if (needSep) {
+                        pw.println();
+                        needSep = false;
+                    }
+                    printed = true;
+                    pw.println("  Active broadcasts [" + mQueueName + "]:");
+                }
+                pw.println("  Broadcast #" + i + ":");
+                br.dump(pw, "    ");
+            }
+            printed = false;
+            needSep = true;
+            for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+                BroadcastRecord br = mOrderedBroadcasts.get(i);
+                if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+                    continue;
+                }
+                if (!printed) {
+                    if (needSep) {
+                        pw.println();
+                    }
+                    needSep = true;
+                    pw.println("  Active ordered broadcasts [" + mQueueName + "]:");
+                }
+                pw.println("  Ordered Broadcast #" + i + ":");
+                mOrderedBroadcasts.get(i).dump(pw, "    ");
+            }
+            if (dumpPackage == null || (mPendingBroadcast != null
+                    && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
+                if (needSep) {
+                    pw.println();
+                }
+                pw.println("  Pending broadcast [" + mQueueName + "]:");
+                if (mPendingBroadcast != null) {
+                    mPendingBroadcast.dump(pw, "    ");
+                } else {
+                    pw.println("    (null)");
+                }
+                needSep = true;
+            }
+        }
+
+        boolean printed = false;
+        for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
+            BroadcastRecord r = mBroadcastHistory[i];
+            if (r == null) {
+                break;
+            }
+            if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
+                continue;
+            }
+            if (!printed) {
+                if (needSep) {
+                    pw.println();
+                }
+                needSep = true;
+                pw.println("  Historical broadcasts [" + mQueueName + "]:");
+                printed = true;
+            }
+            if (dumpAll) {
+                pw.print("  Historical Broadcast #"); pw.print(i); pw.println(":");
+                r.dump(pw, "    ");
+            } else {
+                if (i >= 50) {
+                    pw.println("  ...");
+                    break;
+                }
+                pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
+            }
+        }
+
+        return needSep;
+    }
+}
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index bcb0134..dd560fc 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -59,6 +59,7 @@
     IBinder receiver;       // who is currently running, null if none.
     int state;
     int anrCount;           // has this broadcast record hit any ANRs?
+    BroadcastQueue queue;   // the outbound queue handling this broadcast
 
     static final int IDLE = 0;
     static final int APP_RECEIVE = 1;
@@ -161,11 +162,13 @@
         }
     }
 
-    BroadcastRecord(Intent _intent, ProcessRecord _callerApp, String _callerPackage,
+    BroadcastRecord(BroadcastQueue _queue,
+            Intent _intent, ProcessRecord _callerApp, String _callerPackage,
             int _callingPid, int _callingUid, String _requiredPermission,
             List _receivers, IIntentReceiver _resultTo, int _resultCode,
             String _resultData, Bundle _resultExtras, boolean _serialized,
             boolean _sticky, boolean _initialSticky) {
+        queue = _queue;
         intent = _intent;
         callerApp = _callerApp;
         callerPackage = _callerPackage;
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index f656486..cd72202 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -41,7 +41,7 @@
 
     private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
 
-    private static final int MSG_WRITE = 1;
+    private static final int MSG_WRITE = ActivityManagerService.FIRST_COMPAT_MODE_MSG;
 
     private final Handler mHandler = new Handler() {
         @Override public void handleMessage(Message msg) {
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index abd2a1f..3b6a97c 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -24,6 +24,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.UserId;
 import android.util.Slog;
 
 import java.io.PrintWriter;
@@ -248,7 +249,8 @@
                             owner.broadcastIntentInPackage(key.packageName, uid,
                                     finalIntent, resolvedType,
                                     finishedReceiver, code, null, null,
-                                    requiredPermission, (finishedReceiver != null), false);
+                                requiredPermission, (finishedReceiver != null), false, UserId
+                                        .getUserId(uid));
                             sendFinish = false;
                         } catch (RuntimeException e) {
                             Slog.w(ActivityManagerService.TAG,
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 72292be..b64261d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -28,7 +28,9 @@
 import android.content.res.CompatibilityInfo;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.SystemClock;
+import android.os.UserId;
 import android.util.PrintWriterPrinter;
 import android.util.TimeUtils;
 
@@ -44,6 +46,9 @@
 class ProcessRecord {
     final BatteryStatsImpl.Uid.Proc batteryStats; // where to collect runtime statistics
     final ApplicationInfo info; // all about the first app in the process
+    final boolean isolated;     // true if this is a special isolated process
+    final int uid;              // uid of process; may be different from 'info' if isolated
+    final int userId;           // user of process.
     final String processName;   // name of the process
     // List of packages running in the process
     final HashSet<String> pkgList = new HashSet<String>();
@@ -147,6 +152,12 @@
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
 
+        pw.print(prefix); pw.print("user #"); pw.print(userId);
+                pw.print(" uid="); pw.print(info.uid);
+        if (uid != info.uid) {
+            pw.print(" ISOLATED uid="); pw.print(uid);
+        }
+        pw.println();
         if (info.className != null) {
             pw.print(prefix); pw.print("class="); pw.println(info.className);
         }
@@ -267,9 +278,12 @@
     }
     
     ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread,
-            ApplicationInfo _info, String _processName) {
+            ApplicationInfo _info, String _processName, int _uid) {
         batteryStats = _batteryStats;
         info = _info;
+        isolated = _info.uid != _uid;
+        uid = _uid;
+        userId = UserId.getUserId(_uid);
         processName = _processName;
         pkgList.add(_info.packageName);
         thread = _thread;
@@ -343,7 +357,18 @@
         sb.append(':');
         sb.append(processName);
         sb.append('/');
-        sb.append(info.uid);
+        if (info.uid < Process.FIRST_APPLICATION_UID) {
+            sb.append(uid);
+        } else {
+            sb.append('u');
+            sb.append(userId);
+            sb.append('a');
+            sb.append(info.uid%Process.FIRST_APPLICATION_UID);
+            if (uid != info.uid) {
+                sb.append('i');
+                sb.append(UserId.getAppId(uid) - Process.FIRST_ISOLATED_UID);
+            }
+        }
     }
     
     public String toString() {
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
new file mode 100644
index 0000000..2021e0d
--- /dev/null
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.content.ComponentName;
+import android.os.Binder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserId;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Keeps track of content providers by authority (name) and class. It separates the mapping by
+ * user and ones that are not user-specific (system providers).
+ */
+public class ProviderMap {
+
+    private static final String TAG = "ProviderMap";
+
+    private static final boolean DBG = false;
+
+    private final HashMap<String, ContentProviderRecord> mGlobalByName
+            = new HashMap<String, ContentProviderRecord>();
+    private final HashMap<ComponentName, ContentProviderRecord> mGlobalByClass
+            = new HashMap<ComponentName, ContentProviderRecord>();
+
+    private final SparseArray<HashMap<String, ContentProviderRecord>> mProvidersByNamePerUser
+            = new SparseArray<HashMap<String, ContentProviderRecord>>();
+    private final SparseArray<HashMap<ComponentName, ContentProviderRecord>> mProvidersByClassPerUser
+            = new SparseArray<HashMap<ComponentName, ContentProviderRecord>>();
+
+    ContentProviderRecord getProviderByName(String name) {
+        return getProviderByName(name, -1);
+    }
+
+    ContentProviderRecord getProviderByName(String name, int userId) {
+        if (DBG) {
+            Slog.i(TAG, "getProviderByName: " + name + " , callingUid = " + Binder.getCallingUid());
+        }
+        // Try to find it in the global list
+        ContentProviderRecord record = mGlobalByName.get(name);
+        if (record != null) {
+            return record;
+        }
+
+        // Check the current user's list
+        return getProvidersByName(userId).get(name);
+    }
+
+    ContentProviderRecord getProviderByClass(ComponentName name) {
+        return getProviderByClass(name, -1);
+    }
+
+    ContentProviderRecord getProviderByClass(ComponentName name, int userId) {
+        if (DBG) {
+            Slog.i(TAG, "getProviderByClass: " + name + ", callingUid = " + Binder.getCallingUid());
+        }
+        // Try to find it in the global list
+        ContentProviderRecord record = mGlobalByClass.get(name);
+        if (record != null) {
+            return record;
+        }
+
+        // Check the current user's list
+        return getProvidersByClass(userId).get(name);
+    }
+
+    void putProviderByName(String name, ContentProviderRecord record) {
+        if (DBG) {
+            Slog.i(TAG, "putProviderByName: " + name + " , callingUid = " + Binder.getCallingUid()
+                + ", record uid = " + record.appInfo.uid);
+        }
+        if (record.appInfo.uid < Process.FIRST_APPLICATION_UID) {
+            mGlobalByName.put(name, record);
+        } else {
+            final int userId = UserId.getUserId(record.appInfo.uid);
+            getProvidersByName(userId).put(name, record);
+        }
+    }
+
+    void putProviderByClass(ComponentName name, ContentProviderRecord record) {
+        if (DBG) {
+            Slog.i(TAG, "putProviderByClass: " + name + " , callingUid = " + Binder.getCallingUid()
+                + ", record uid = " + record.appInfo.uid);
+        }
+        if (record.appInfo.uid < Process.FIRST_APPLICATION_UID) {
+            mGlobalByClass.put(name, record);
+        } else {
+            final int userId = UserId.getUserId(record.appInfo.uid);
+            getProvidersByClass(userId).put(name, record);
+        }
+    }
+
+    void removeProviderByName(String name, int optionalUserId) {
+        if (mGlobalByName.containsKey(name)) {
+            if (DBG)
+                Slog.i(TAG, "Removing from globalByName name=" + name);
+            mGlobalByName.remove(name);
+        } else {
+            // TODO: Verify this works, i.e., the caller happens to be from the correct user
+            if (DBG)
+                Slog.i(TAG,
+                        "Removing from providersByName name=" + name + " user="
+                        + (optionalUserId == -1 ? Binder.getOrigCallingUser() : optionalUserId));
+            getProvidersByName(optionalUserId).remove(name);
+        }
+    }
+
+    void removeProviderByClass(ComponentName name, int optionalUserId) {
+        if (mGlobalByClass.containsKey(name)) {
+            if (DBG)
+                Slog.i(TAG, "Removing from globalByClass name=" + name);
+            mGlobalByClass.remove(name);
+        } else {
+            if (DBG)
+                Slog.i(TAG,
+                        "Removing from providersByClass name=" + name + " user="
+                        + (optionalUserId == -1 ? Binder.getOrigCallingUser() : optionalUserId));
+            getProvidersByClass(optionalUserId).remove(name);
+        }
+    }
+
+    private HashMap<String, ContentProviderRecord> getProvidersByName(int optionalUserId) {
+        final int userId = optionalUserId >= 0
+                ? optionalUserId : Binder.getOrigCallingUser();
+        final HashMap<String, ContentProviderRecord> map = mProvidersByNamePerUser.get(userId);
+        if (map == null) {
+            HashMap<String, ContentProviderRecord> newMap = new HashMap<String, ContentProviderRecord>();
+            mProvidersByNamePerUser.put(userId, newMap);
+            return newMap;
+        } else {
+            return map;
+        }
+    }
+
+    HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int optionalUserId) {
+        final int userId = optionalUserId >= 0
+                ? optionalUserId : Binder.getOrigCallingUser();
+        final HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.get(userId);
+        if (map == null) {
+            HashMap<ComponentName, ContentProviderRecord> newMap = new HashMap<ComponentName, ContentProviderRecord>();
+            mProvidersByClassPerUser.put(userId, newMap);
+            return newMap;
+        } else {
+            return map;
+        }
+    }
+
+    private void dumpProvidersByClassLocked(PrintWriter pw, boolean dumpAll,
+            HashMap<ComponentName, ContentProviderRecord> map) {
+        Iterator<Map.Entry<ComponentName, ContentProviderRecord>> it = map.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<ComponentName, ContentProviderRecord> e = it.next();
+            ContentProviderRecord r = e.getValue();
+            if (dumpAll) {
+                pw.print("  * ");
+                pw.println(r);
+                r.dump(pw, "    ");
+            } else {
+                pw.print("  * ");
+                pw.print(r.name.toShortString());
+                /*
+                if (r.app != null) {
+                    pw.println(":");
+                    pw.print("      ");
+                    pw.println(r.app);
+                } else {
+                    pw.println();
+                }
+                */
+            }
+        }
+    }
+
+    private void dumpProvidersByNameLocked(PrintWriter pw,
+            HashMap<String, ContentProviderRecord> map) {
+        Iterator<Map.Entry<String, ContentProviderRecord>> it = map.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, ContentProviderRecord> e = it.next();
+            ContentProviderRecord r = e.getValue();
+            pw.print("  ");
+            pw.print(e.getKey());
+            pw.print(": ");
+            pw.println(r);
+        }
+    }
+
+    void dumpProvidersLocked(PrintWriter pw, boolean dumpAll) {
+        boolean needSep = false;
+        if (mGlobalByClass.size() > 0) {
+            if (needSep)
+                pw.println(" ");
+            pw.println("  Published content providers (by class):");
+            dumpProvidersByClassLocked(pw, dumpAll, mGlobalByClass);
+            pw.println(" ");
+        }
+
+        if (mProvidersByClassPerUser.size() > 1) {
+            for (int i = 0; i < mProvidersByClassPerUser.size(); i++) {
+                HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(i);
+                pw.println("  User " + mProvidersByClassPerUser.keyAt(i) + ":");
+                dumpProvidersByClassLocked(pw, dumpAll, map);
+                pw.println(" ");
+            }
+        } else if (mProvidersByClassPerUser.size() == 1) {
+            HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(0);
+            dumpProvidersByClassLocked(pw, dumpAll, map);
+        }
+        needSep = true;
+
+        if (dumpAll) {
+            pw.println(" ");
+            pw.println("  Authority to provider mappings:");
+            dumpProvidersByNameLocked(pw, mGlobalByName);
+
+            for (int i = 0; i < mProvidersByNamePerUser.size(); i++) {
+                if (i > 0) {
+                    pw.println("  User " + mProvidersByNamePerUser.keyAt(i) + ":");
+                }
+                dumpProvidersByNameLocked(pw, mProvidersByNamePerUser.valueAt(i));
+            }
+        }
+    }
+
+    protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
+            int opti, boolean dumpAll) {
+        ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
+
+        if ("all".equals(name)) {
+            synchronized (this) {
+                for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
+                    providers.add(r1);
+                }
+            }
+        } else {
+            ComponentName componentName = name != null
+                    ? ComponentName.unflattenFromString(name) : null;
+            int objectId = 0;
+            if (componentName == null) {
+                // Not a '/' separated full component name; maybe an object ID?
+                try {
+                    objectId = Integer.parseInt(name, 16);
+                    name = null;
+                    componentName = null;
+                } catch (RuntimeException e) {
+                }
+            }
+
+            synchronized (this) {
+                for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
+                    if (componentName != null) {
+                        if (r1.name.equals(componentName)) {
+                            providers.add(r1);
+                        }
+                    } else if (name != null) {
+                        if (r1.name.flattenToString().contains(name)) {
+                            providers.add(r1);
+                        }
+                    } else if (System.identityHashCode(r1) == objectId) {
+                        providers.add(r1);
+                    }
+                }
+            }
+        }
+
+        if (providers.size() <= 0) {
+            return false;
+        }
+
+        boolean needSep = false;
+        for (int i=0; i<providers.size(); i++) {
+            if (needSep) {
+                pw.println();
+            }
+            needSep = true;
+            dumpProvider("", fd, pw, providers.get(i), args, dumpAll);
+        }
+        return true;
+    }
+
+    /**
+     * Invokes IApplicationThread.dumpProvider() on the thread of the specified provider if
+     * there is a thread associated with the provider.
+     */
+    private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw,
+            final ContentProviderRecord r, String[] args, boolean dumpAll) {
+        String innerPrefix = prefix + "  ";
+        synchronized (this) {
+            pw.print(prefix); pw.print("PROVIDER ");
+                    pw.print(r);
+                    pw.print(" pid=");
+                    if (r.proc != null) pw.println(r.proc.pid);
+                    else pw.println("(not running)");
+            if (dumpAll) {
+                r.dump(pw, innerPrefix);
+            }
+        }
+        if (r.proc != null && r.proc.thread != null) {
+            pw.println("    Client:");
+            pw.flush();
+            try {
+                TransferPipe tp = new TransferPipe();
+                try {
+                    r.proc.thread.dumpProvider(
+                            tp.getWriteFd().getFileDescriptor(), r.provider.asBinder(), args);
+                    tp.setBufferPrefix("      ");
+                    // Short timeout, since blocking here can
+                    // deadlock with the application.
+                    tp.go(fd, 2000);
+                } finally {
+                    tp.kill();
+                }
+            } catch (IOException ex) {
+                pw.println("      Failure while dumping the provider: " + ex);
+            } catch (RemoteException ex) {
+                pw.println("      Got a RemoteException while dumping the service");
+            }
+        }
+    }
+
+
+}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 257113b..daa3653 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -25,11 +25,13 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.UserId;
 import android.util.Slog;
 import android.util.TimeUtils;
 
@@ -60,6 +62,7 @@
                             // all information about the service.
     final ApplicationInfo appInfo;
                             // information about service's app.
+    final int userId;       // user that this service is running as
     final String packageName; // the package implementing intent's component
     final String processName; // process where this component wants to run
     final String permission;// permission needed to access service
@@ -77,6 +80,7 @@
                             // IBinder -> ConnectionRecord of all bound clients
 
     ProcessRecord app;      // where this service is running or null.
+    ProcessRecord isolatedProc; // keep track of isolated process, if requested
     boolean isForeground;   // is service currently in foreground mode?
     int foregroundId;       // Notification ID of last foreground req.
     Notification foregroundNoti; // Notification record of foreground state.
@@ -207,6 +211,9 @@
         }
         pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
         pw.print(prefix); pw.print("app="); pw.println(app);
+        if (isolatedProc != null) {
+            pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
+        }
         if (isForeground || foregroundId != 0) {
             pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
                     pw.print(" foregroundId="); pw.print(foregroundId);
@@ -289,6 +296,7 @@
         this.restarter = restarter;
         createTime = SystemClock.elapsedRealtime();
         lastActivity = SystemClock.uptimeMillis();
+        userId = UserId.getUserId(appInfo.uid);
     }
 
     public AppBindRecord retrieveAppBindingLocked(Intent intent,
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index de3129b..47ec218 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -19,7 +19,9 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
+import android.os.UserId;
 
 import java.io.PrintWriter;
 
@@ -37,6 +39,7 @@
     boolean askedCompatMode;// Have asked the user about compat mode for this task.
 
     String stringName;      // caching of toString() result.
+    int userId; // user for which this task was created
     
     TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
         taskId = _taskId;
@@ -84,13 +87,17 @@
                 origActivity = new ComponentName(info.packageName, info.name);
             }
         }
-        
+
         if (intent != null &&
                 (intent.getFlags()&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
             // Once we are set to an Intent with this flag, we count this
             // task as having a true root activity.
             rootWasReset = true;
         }
+
+        if (info.applicationInfo != null) {
+            userId = UserId.getUserId(info.applicationInfo.uid);
+        }
     }
     
     void dump(PrintWriter pw, String prefix) {
@@ -154,6 +161,8 @@
         } else {
             sb.append(" ??");
         }
+        sb.append(" U ");
+        sb.append(userId);
         sb.append('}');
         return stringName = sb.toString();
     }
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 51adebe..a890068 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -48,6 +48,7 @@
 import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
 import static android.net.NetworkTemplate.MATCH_WIFI;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
@@ -154,10 +155,7 @@
     private static final int VERSION_ADDED_SNOOZE = 2;
     private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3;
     private static final int VERSION_ADDED_METERED = 4;
-
-    private static final long KB_IN_BYTES = 1024;
-    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
-    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
+    private static final int VERSION_SPLIT_SNOOZE = 5;
 
     // @VisibleForTesting
     public static final int TYPE_WARNING = 0x1;
@@ -176,6 +174,8 @@
     private static final String ATTR_WARNING_BYTES = "warningBytes";
     private static final String ATTR_LIMIT_BYTES = "limitBytes";
     private static final String ATTR_LAST_SNOOZE = "lastSnooze";
+    private static final String ATTR_LAST_WARNING_SNOOZE = "lastWarningSnooze";
+    private static final String ATTR_LAST_LIMIT_SNOOZE = "lastLimitSnooze";
     private static final String ATTR_METERED = "metered";
     private static final String ATTR_UID = "uid";
     private static final String ATTR_POLICY = "policy";
@@ -184,7 +184,9 @@
 
     // @VisibleForTesting
     public static final String ACTION_ALLOW_BACKGROUND =
-            "com.android.server.action.ACTION_ALLOW_BACKGROUND";
+            "com.android.server.net.action.ALLOW_BACKGROUND";
+    public static final String ACTION_SNOOZE_WARNING =
+            "com.android.server.net.action.SNOOZE_WARNING";
 
     private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
 
@@ -193,6 +195,7 @@
     private static final int MSG_FOREGROUND_ACTIVITIES_CHANGED = 3;
     private static final int MSG_PROCESS_DIED = 4;
     private static final int MSG_LIMIT_REACHED = 5;
+    private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
 
     private final Context mContext;
     private final IActivityManager mActivityManager;
@@ -333,6 +336,11 @@
         final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
         mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
 
+        // listen for snooze warning from notifications
+        final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
+        mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
+                MANAGE_NETWORK_POLICY, mHandler);
+
     }
 
     private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -418,6 +426,21 @@
     };
 
     /**
+     * Receiver that watches for {@link Notification} control of
+     * {@link NetworkPolicy#lastWarningSnooze}.
+     */
+    private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // on background handler thread, and verified MANAGE_NETWORK_POLICY
+            // permission above.
+
+            final NetworkTemplate template = intent.getParcelableExtra(EXTRA_NETWORK_TEMPLATE);
+            performSnooze(template, TYPE_WARNING);
+        }
+    };
+
+    /**
      * Observer that watches for {@link INetworkManagementService} alerts.
      */
     private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() {
@@ -458,7 +481,7 @@
             final long totalBytes = getTotalBytes(policy.template, start, end);
 
             if (policy.isOverLimit(totalBytes)) {
-                if (policy.lastSnooze >= start) {
+                if (policy.lastLimitSnooze >= start) {
                     enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
                 } else {
                     enqueueNotification(policy, TYPE_LIMIT, totalBytes);
@@ -468,7 +491,7 @@
             } else {
                 notifyUnderLimitLocked(policy.template);
 
-                if (policy.warningBytes != WARNING_DISABLED && totalBytes >= policy.warningBytes) {
+                if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) {
                     enqueueNotification(policy, TYPE_WARNING, totalBytes);
                 }
             }
@@ -534,7 +557,7 @@
         final String tag = buildNotificationTag(policy, type);
         final Notification.Builder builder = new Notification.Builder(mContext);
         builder.setOnlyAlertOnce(true);
-        builder.setOngoing(true);
+        builder.setWhen(0L);
 
         final Resources res = mContext.getResources();
         switch (type) {
@@ -547,9 +570,14 @@
                 builder.setContentTitle(title);
                 builder.setContentText(body);
 
-                final Intent intent = buildViewDataUsageIntent(policy.template);
+                final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
+                builder.setDeleteIntent(PendingIntent.getBroadcast(
+                        mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+
+                final Intent viewIntent = buildViewDataUsageIntent(policy.template);
                 builder.setContentIntent(PendingIntent.getActivity(
-                        mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+                        mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+
                 break;
             }
             case TYPE_LIMIT: {
@@ -574,6 +602,7 @@
                         break;
                 }
 
+                builder.setOngoing(true);
                 builder.setSmallIcon(R.drawable.stat_notify_disabled);
                 builder.setTicker(title);
                 builder.setContentTitle(title);
@@ -608,6 +637,7 @@
                         break;
                 }
 
+                builder.setOngoing(true);
                 builder.setSmallIcon(R.drawable.stat_notify_error);
                 builder.setTicker(title);
                 builder.setContentTitle(title);
@@ -720,10 +750,11 @@
             final long totalBytes = getTotalBytes(policy.template, start, end);
 
             // disable data connection when over limit and not snoozed
-            final boolean overLimit = policy.isOverLimit(totalBytes) && policy.lastSnooze < start;
-            final boolean enabled = !overLimit;
+            final boolean overLimitWithoutSnooze = policy.isOverLimit(totalBytes)
+                    && policy.lastLimitSnooze < start;
+            final boolean networkEnabled = !overLimitWithoutSnooze;
 
-            setNetworkTemplateEnabled(policy.template, enabled);
+            setNetworkTemplateEnabled(policy.template, networkEnabled);
         }
     }
 
@@ -827,7 +858,7 @@
                     // metered network, but no policy limit; we still need to
                     // restrict apps, so push really high quota.
                     quotaBytes = Long.MAX_VALUE;
-                } else if (policy.lastSnooze >= start) {
+                } else if (policy.lastLimitSnooze >= start) {
                     // snoozing past quota, but we still need to restrict apps,
                     // so push really high quota.
                     quotaBytes = Long.MAX_VALUE;
@@ -896,8 +927,8 @@
             final int cycleDay = time.monthDay;
 
             final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
-            mNetworkPolicy.put(template, new NetworkPolicy(
-                    template, cycleDay, warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, true));
+            mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, warningBytes,
+                    LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true));
             writePolicyLocked();
         }
     }
@@ -935,11 +966,13 @@
                         final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
                         final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
                         final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
-                        final long lastSnooze;
-                        if (version >= VERSION_ADDED_SNOOZE) {
-                            lastSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
+                        final long lastLimitSnooze;
+                        if (version >= VERSION_SPLIT_SNOOZE) {
+                            lastLimitSnooze = readLongAttribute(in, ATTR_LAST_LIMIT_SNOOZE);
+                        } else if (version >= VERSION_ADDED_SNOOZE) {
+                            lastLimitSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
                         } else {
-                            lastSnooze = SNOOZE_NEVER;
+                            lastLimitSnooze = SNOOZE_NEVER;
                         }
                         final boolean metered;
                         if (version >= VERSION_ADDED_METERED) {
@@ -955,11 +988,18 @@
                                     metered = false;
                             }
                         }
+                        final long lastWarningSnooze;
+                        if (version >= VERSION_SPLIT_SNOOZE) {
+                            lastWarningSnooze = readLongAttribute(in, ATTR_LAST_WARNING_SNOOZE);
+                        } else {
+                            lastWarningSnooze = SNOOZE_NEVER;
+                        }
 
                         final NetworkTemplate template = new NetworkTemplate(
                                 networkTemplate, subscriberId);
-                        mNetworkPolicy.put(template, new NetworkPolicy(
-                                template, cycleDay, warningBytes, limitBytes, lastSnooze, metered));
+                        mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
+                                warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze,
+                                metered));
 
                     } else if (TAG_UID_POLICY.equals(tag)) {
                         final int uid = readIntAttribute(in, ATTR_UID);
@@ -1014,7 +1054,7 @@
             out.startDocument(null, true);
 
             out.startTag(null, TAG_POLICY_LIST);
-            writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_METERED);
+            writeIntAttribute(out, ATTR_VERSION, VERSION_SPLIT_SNOOZE);
             writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
 
             // write all known network policies
@@ -1030,7 +1070,8 @@
                 writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
                 writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
                 writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
-                writeLongAttribute(out, ATTR_LAST_SNOOZE, policy.lastSnooze);
+                writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze);
+                writeLongAttribute(out, ATTR_LAST_LIMIT_SNOOZE, policy.lastLimitSnooze);
                 writeBooleanAttribute(out, ATTR_METERED, policy.metered);
                 out.endTag(null, TAG_NETWORK_POLICY);
             }
@@ -1141,9 +1182,12 @@
     }
 
     @Override
-    public void snoozePolicy(NetworkTemplate template) {
+    public void snoozeLimit(NetworkTemplate template) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+        performSnooze(template, TYPE_LIMIT);
+    }
 
+    private void performSnooze(NetworkTemplate template, int type) {
         maybeRefreshTrustedTime();
         final long currentTime = currentTimeMillis();
         synchronized (mRulesLock) {
@@ -1153,7 +1197,16 @@
                 throw new IllegalArgumentException("unable to find policy for " + template);
             }
 
-            policy.lastSnooze = currentTime;
+            switch (type) {
+                case TYPE_WARNING:
+                    policy.lastWarningSnooze = currentTime;
+                    break;
+                case TYPE_LIMIT:
+                    policy.lastLimitSnooze = currentTime;
+                    break;
+                default:
+                    throw new IllegalArgumentException("unexpected type");
+            }
 
             updateNetworkEnabledLocked();
             updateNetworkRulesLocked();
@@ -1173,6 +1226,9 @@
             updateNotificationsLocked();
             writePolicyLocked();
         }
+
+        mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
+                .sendToTarget();
     }
 
     @Override
@@ -1246,12 +1302,17 @@
         }
 
         synchronized (mRulesLock) {
-            if (argSet.contains("unsnooze")) {
+            if (argSet.contains("--unsnooze")) {
                 for (NetworkPolicy policy : mNetworkPolicy.values()) {
-                    policy.lastSnooze = SNOOZE_NEVER;
+                    policy.clearSnooze();
                 }
+
+                updateNetworkEnabledLocked();
+                updateNetworkRulesLocked();
+                updateNotificationsLocked();
                 writePolicyLocked();
-                fout.println("Wiped snooze timestamps");
+
+                fout.println("Cleared snooze timestamps");
                 return;
             }
 
@@ -1516,6 +1577,20 @@
                     }
                     return true;
                 }
+                case MSG_RESTRICT_BACKGROUND_CHANGED: {
+                    final boolean restrictBackground = msg.arg1 != 0;
+                    final int length = mListeners.beginBroadcast();
+                    for (int i = 0; i < length; i++) {
+                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+                        if (listener != null) {
+                            try {
+                                listener.onRestrictBackgroundChanged(restrictBackground);
+                            } catch (RemoteException e) {
+                            }
+                        }
+                    }
+                    mListeners.finishBroadcast();
+                }
                 default: {
                     return false;
                 }
@@ -1573,6 +1648,9 @@
     private long getTotalBytes(NetworkTemplate template, long start, long end) {
         try {
             return mNetworkStats.getSummaryForNetwork(template, start, end).getTotalBytes();
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "problem reading network stats: " + e);
+            return 0;
         } catch (RemoteException e) {
             // ignored; service lives in system_server
             return 0;
@@ -1596,6 +1674,12 @@
         return new Intent(ACTION_ALLOW_BACKGROUND);
     }
 
+    private static Intent buildSnoozeWarningIntent(NetworkTemplate template) {
+        final Intent intent = new Intent(ACTION_SNOOZE_WARNING);
+        intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
+        return intent;
+    }
+
     private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) {
         final Intent intent = new Intent();
         intent.setComponent(new ComponentName(
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java
new file mode 100644
index 0000000..70038d9
--- /dev/null
+++ b/services/java/com/android/server/net/NetworkStatsCollection.java
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.SET_ALL;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
+import static android.net.TrafficStats.UID_REMOVED;
+
+import android.net.NetworkIdentity;
+import android.net.NetworkStats;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.net.TrafficStats;
+import android.text.format.DateUtils;
+
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.FileRotator;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Objects;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ProtocolException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import libcore.io.IoUtils;
+
+/**
+ * Collection of {@link NetworkStatsHistory}, stored based on combined key of
+ * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself.
+ */
+public class NetworkStatsCollection implements FileRotator.Reader {
+    private static final String TAG = "NetworkStatsCollection";
+
+    /** File header magic number: "ANET" */
+    private static final int FILE_MAGIC = 0x414E4554;
+
+    private static final int VERSION_NETWORK_INIT = 1;
+
+    private static final int VERSION_UID_INIT = 1;
+    private static final int VERSION_UID_WITH_IDENT = 2;
+    private static final int VERSION_UID_WITH_TAG = 3;
+    private static final int VERSION_UID_WITH_SET = 4;
+
+    private static final int VERSION_UNIFIED_INIT = 16;
+
+    private HashMap<Key, NetworkStatsHistory> mStats = Maps.newHashMap();
+
+    private long mBucketDuration;
+
+    private long mStartMillis;
+    private long mEndMillis;
+    private long mTotalBytes;
+    private boolean mDirty;
+
+    public NetworkStatsCollection(long bucketDuration) {
+        mBucketDuration = bucketDuration;
+        reset();
+    }
+
+    public void reset() {
+        mStats.clear();
+        mStartMillis = Long.MAX_VALUE;
+        mEndMillis = Long.MIN_VALUE;
+        mTotalBytes = 0;
+        mDirty = false;
+    }
+
+    public long getStartMillis() {
+        return mStartMillis;
+    }
+
+    public long getEndMillis() {
+        return mEndMillis;
+    }
+
+    public long getTotalBytes() {
+        return mTotalBytes;
+    }
+
+    public boolean isDirty() {
+        return mDirty;
+    }
+
+    public void clearDirty() {
+        mDirty = false;
+    }
+
+    public boolean isEmpty() {
+        return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
+    }
+
+    /**
+     * Combine all {@link NetworkStatsHistory} in this collection which match
+     * the requested parameters.
+     */
+    public NetworkStatsHistory getHistory(
+            NetworkTemplate template, int uid, int set, int tag, int fields) {
+        final NetworkStatsHistory combined = new NetworkStatsHistory(
+                mBucketDuration, estimateBuckets(), fields);
+        for (Map.Entry<Key, NetworkStatsHistory> entry : mStats.entrySet()) {
+            final Key key = entry.getKey();
+            final boolean setMatches = set == SET_ALL || key.set == set;
+            if (key.uid == uid && setMatches && key.tag == tag
+                    && templateMatches(template, key.ident)) {
+                combined.recordEntireHistory(entry.getValue());
+            }
+        }
+        return combined;
+    }
+
+    /**
+     * Summarize all {@link NetworkStatsHistory} in this collection which match
+     * the requested parameters.
+     */
+    public NetworkStats getSummary(NetworkTemplate template, long start, long end) {
+        final long now = System.currentTimeMillis();
+
+        final NetworkStats stats = new NetworkStats(end - start, 24);
+        final NetworkStats.Entry entry = new NetworkStats.Entry();
+        NetworkStatsHistory.Entry historyEntry = null;
+
+        for (Map.Entry<Key, NetworkStatsHistory> mapEntry : mStats.entrySet()) {
+            final Key key = mapEntry.getKey();
+            if (templateMatches(template, key.ident)) {
+                final NetworkStatsHistory history = mapEntry.getValue();
+                historyEntry = history.getValues(start, end, now, historyEntry);
+
+                entry.iface = IFACE_ALL;
+                entry.uid = key.uid;
+                entry.set = key.set;
+                entry.tag = key.tag;
+                entry.rxBytes = historyEntry.rxBytes;
+                entry.rxPackets = historyEntry.rxPackets;
+                entry.txBytes = historyEntry.txBytes;
+                entry.txPackets = historyEntry.txPackets;
+                entry.operations = historyEntry.operations;
+
+                if (!entry.isEmpty()) {
+                    stats.combineValues(entry);
+                }
+            }
+        }
+
+        return stats;
+    }
+
+    /**
+     * Record given {@link NetworkStats.Entry} into this collection.
+     */
+    public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start,
+            long end, NetworkStats.Entry entry) {
+        noteRecordedHistory(start, end, entry.rxBytes + entry.txBytes);
+        findOrCreateHistory(ident, uid, set, tag).recordData(start, end, entry);
+    }
+
+    /**
+     * Record given {@link NetworkStatsHistory} into this collection.
+     */
+    private void recordHistory(Key key, NetworkStatsHistory history) {
+        if (history.size() == 0) return;
+        noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes());
+
+        final NetworkStatsHistory existing = mStats.get(key);
+        if (existing != null) {
+            existing.recordEntireHistory(history);
+        } else {
+            mStats.put(key, history);
+        }
+    }
+
+    /**
+     * Record all {@link NetworkStatsHistory} contained in the given collection
+     * into this collection.
+     */
+    public void recordCollection(NetworkStatsCollection another) {
+        for (Map.Entry<Key, NetworkStatsHistory> entry : another.mStats.entrySet()) {
+            recordHistory(entry.getKey(), entry.getValue());
+        }
+    }
+
+    private NetworkStatsHistory findOrCreateHistory(
+            NetworkIdentitySet ident, int uid, int set, int tag) {
+        final Key key = new Key(ident, uid, set, tag);
+        final NetworkStatsHistory existing = mStats.get(key);
+
+        // update when no existing, or when bucket duration changed
+        NetworkStatsHistory updated = null;
+        if (existing == null) {
+            updated = new NetworkStatsHistory(mBucketDuration, 10);
+        } else if (existing.getBucketDuration() != mBucketDuration) {
+            updated = new NetworkStatsHistory(existing, mBucketDuration);
+        }
+
+        if (updated != null) {
+            mStats.put(key, updated);
+            return updated;
+        } else {
+            return existing;
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void read(InputStream in) throws IOException {
+        read(new DataInputStream(in));
+    }
+
+    public void read(DataInputStream in) throws IOException {
+        // verify file magic header intact
+        final int magic = in.readInt();
+        if (magic != FILE_MAGIC) {
+            throw new ProtocolException("unexpected magic: " + magic);
+        }
+
+        final int version = in.readInt();
+        switch (version) {
+            case VERSION_UNIFIED_INIT: {
+                // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
+                final int identSize = in.readInt();
+                for (int i = 0; i < identSize; i++) {
+                    final NetworkIdentitySet ident = new NetworkIdentitySet(in);
+
+                    final int size = in.readInt();
+                    for (int j = 0; j < size; j++) {
+                        final int uid = in.readInt();
+                        final int set = in.readInt();
+                        final int tag = in.readInt();
+
+                        final Key key = new Key(ident, uid, set, tag);
+                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
+                        recordHistory(key, history);
+                    }
+                }
+                break;
+            }
+            default: {
+                throw new ProtocolException("unexpected version: " + version);
+            }
+        }
+    }
+
+    public void write(DataOutputStream out) throws IOException {
+        // cluster key lists grouped by ident
+        final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = Maps.newHashMap();
+        for (Key key : mStats.keySet()) {
+            ArrayList<Key> keys = keysByIdent.get(key.ident);
+            if (keys == null) {
+                keys = Lists.newArrayList();
+                keysByIdent.put(key.ident, keys);
+            }
+            keys.add(key);
+        }
+
+        out.writeInt(FILE_MAGIC);
+        out.writeInt(VERSION_UNIFIED_INIT);
+
+        out.writeInt(keysByIdent.size());
+        for (NetworkIdentitySet ident : keysByIdent.keySet()) {
+            final ArrayList<Key> keys = keysByIdent.get(ident);
+            ident.writeToStream(out);
+
+            out.writeInt(keys.size());
+            for (Key key : keys) {
+                final NetworkStatsHistory history = mStats.get(key);
+                out.writeInt(key.uid);
+                out.writeInt(key.set);
+                out.writeInt(key.tag);
+                history.writeToStream(out);
+            }
+        }
+
+        out.flush();
+    }
+
+    @Deprecated
+    public void readLegacyNetwork(File file) throws IOException {
+        final AtomicFile inputFile = new AtomicFile(file);
+
+        DataInputStream in = null;
+        try {
+            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
+
+            // verify file magic header intact
+            final int magic = in.readInt();
+            if (magic != FILE_MAGIC) {
+                throw new ProtocolException("unexpected magic: " + magic);
+            }
+
+            final int version = in.readInt();
+            switch (version) {
+                case VERSION_NETWORK_INIT: {
+                    // network := size *(NetworkIdentitySet NetworkStatsHistory)
+                    final int size = in.readInt();
+                    for (int i = 0; i < size; i++) {
+                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
+                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
+
+                        final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE);
+                        recordHistory(key, history);
+                    }
+                    break;
+                }
+                default: {
+                    throw new ProtocolException("unexpected version: " + version);
+                }
+            }
+        } catch (FileNotFoundException e) {
+            // missing stats is okay, probably first boot
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    @Deprecated
+    public void readLegacyUid(File file, boolean onlyTags) throws IOException {
+        final AtomicFile inputFile = new AtomicFile(file);
+
+        DataInputStream in = null;
+        try {
+            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
+
+            // verify file magic header intact
+            final int magic = in.readInt();
+            if (magic != FILE_MAGIC) {
+                throw new ProtocolException("unexpected magic: " + magic);
+            }
+
+            final int version = in.readInt();
+            switch (version) {
+                case VERSION_UID_INIT: {
+                    // uid := size *(UID NetworkStatsHistory)
+
+                    // drop this data version, since we don't have a good
+                    // mapping into NetworkIdentitySet.
+                    break;
+                }
+                case VERSION_UID_WITH_IDENT: {
+                    // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
+
+                    // drop this data version, since this version only existed
+                    // for a short time.
+                    break;
+                }
+                case VERSION_UID_WITH_TAG:
+                case VERSION_UID_WITH_SET: {
+                    // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
+                    final int identSize = in.readInt();
+                    for (int i = 0; i < identSize; i++) {
+                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
+
+                        final int size = in.readInt();
+                        for (int j = 0; j < size; j++) {
+                            final int uid = in.readInt();
+                            final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
+                                    : SET_DEFAULT;
+                            final int tag = in.readInt();
+
+                            final Key key = new Key(ident, uid, set, tag);
+                            final NetworkStatsHistory history = new NetworkStatsHistory(in);
+
+                            if ((tag == TAG_NONE) != onlyTags) {
+                                recordHistory(key, history);
+                            }
+                        }
+                    }
+                    break;
+                }
+                default: {
+                    throw new ProtocolException("unexpected version: " + version);
+                }
+            }
+        } catch (FileNotFoundException e) {
+            // missing stats is okay, probably first boot
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    /**
+     * Remove any {@link NetworkStatsHistory} attributed to the requested UID,
+     * moving any {@link NetworkStats#TAG_NONE} series to
+     * {@link TrafficStats#UID_REMOVED}.
+     */
+    public void removeUid(int uid) {
+        final ArrayList<Key> knownKeys = Lists.newArrayList();
+        knownKeys.addAll(mStats.keySet());
+
+        // migrate all UID stats into special "removed" bucket
+        for (Key key : knownKeys) {
+            if (key.uid == uid) {
+                // only migrate combined TAG_NONE history
+                if (key.tag == TAG_NONE) {
+                    final NetworkStatsHistory uidHistory = mStats.get(key);
+                    final NetworkStatsHistory removedHistory = findOrCreateHistory(
+                            key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
+                    removedHistory.recordEntireHistory(uidHistory);
+                }
+                mStats.remove(key);
+                mDirty = true;
+            }
+        }
+    }
+
+    private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) {
+        if (startMillis < mStartMillis) mStartMillis = startMillis;
+        if (endMillis > mEndMillis) mEndMillis = endMillis;
+        mTotalBytes += totalBytes;
+        mDirty = true;
+    }
+
+    private int estimateBuckets() {
+        return (int) (Math.min(mEndMillis - mStartMillis, DateUtils.WEEK_IN_MILLIS * 5)
+                / mBucketDuration);
+    }
+
+    public void dump(IndentingPrintWriter pw) {
+        final ArrayList<Key> keys = Lists.newArrayList();
+        keys.addAll(mStats.keySet());
+        Collections.sort(keys);
+
+        for (Key key : keys) {
+            pw.print("ident="); pw.print(key.ident.toString());
+            pw.print(" uid="); pw.print(key.uid);
+            pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
+            pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
+
+            final NetworkStatsHistory history = mStats.get(key);
+            pw.increaseIndent();
+            history.dump(pw, true);
+            pw.decreaseIndent();
+        }
+    }
+
+    /**
+     * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
+     * in the given {@link NetworkIdentitySet}.
+     */
+    private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
+        for (NetworkIdentity ident : identSet) {
+            if (template.matches(ident)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static class Key implements Comparable<Key> {
+        public final NetworkIdentitySet ident;
+        public final int uid;
+        public final int set;
+        public final int tag;
+
+        private final int hashCode;
+
+        public Key(NetworkIdentitySet ident, int uid, int set, int tag) {
+            this.ident = ident;
+            this.uid = uid;
+            this.set = set;
+            this.tag = tag;
+            hashCode = Objects.hashCode(ident, uid, set, tag);
+        }
+
+        @Override
+        public int hashCode() {
+            return hashCode;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Key) {
+                final Key key = (Key) obj;
+                return uid == key.uid && set == key.set && tag == key.tag
+                        && Objects.equal(ident, key.ident);
+            }
+            return false;
+        }
+
+        /** {@inheritDoc} */
+        public int compareTo(Key another) {
+            return Integer.compare(uid, another.uid);
+        }
+    }
+}
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java
new file mode 100644
index 0000000..240cc1c
--- /dev/null
+++ b/services/java/com/android/server/net/NetworkStatsRecorder.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static android.net.NetworkStats.TAG_NONE;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.net.NetworkStats;
+import android.net.NetworkStats.NonMonotonicObserver;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.net.TrafficStats;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.util.FileRotator;
+import com.android.internal.util.IndentingPrintWriter;
+import com.google.android.collect.Sets;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.ref.WeakReference;
+import java.util.HashSet;
+import java.util.Map;
+
+/**
+ * Logic to record deltas between periodic {@link NetworkStats} snapshots into
+ * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
+ * Keeps pending changes in memory until they pass a specific threshold, in
+ * bytes. Uses {@link FileRotator} for persistence logic.
+ * <p>
+ * Not inherently thread safe.
+ */
+public class NetworkStatsRecorder {
+    private static final String TAG = "NetworkStatsRecorder";
+    private static final boolean LOGD = true;
+    private static final boolean LOGV = false;
+
+    private final FileRotator mRotator;
+    private final NonMonotonicObserver<String> mObserver;
+    private final String mCookie;
+
+    private final long mBucketDuration;
+    private final long mPersistThresholdBytes;
+    private final boolean mOnlyTags;
+
+    private NetworkStats mLastSnapshot;
+
+    private final NetworkStatsCollection mPending;
+    private final NetworkStatsCollection mSinceBoot;
+
+    private final CombiningRewriter mPendingRewriter;
+
+    private WeakReference<NetworkStatsCollection> mComplete;
+
+    public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
+            String cookie, long bucketDuration, long persistThresholdBytes, boolean onlyTags) {
+        mRotator = checkNotNull(rotator, "missing FileRotator");
+        mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
+        mCookie = cookie;
+
+        mBucketDuration = bucketDuration;
+        mPersistThresholdBytes = persistThresholdBytes;
+        mOnlyTags = onlyTags;
+
+        mPending = new NetworkStatsCollection(bucketDuration);
+        mSinceBoot = new NetworkStatsCollection(bucketDuration);
+
+        mPendingRewriter = new CombiningRewriter(mPending);
+    }
+
+    public void resetLocked() {
+        mLastSnapshot = null;
+        mPending.reset();
+        mSinceBoot.reset();
+        mComplete.clear();
+    }
+
+    public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
+        return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null);
+    }
+
+    /**
+     * Load complete history represented by {@link FileRotator}. Caches
+     * internally as a {@link WeakReference}, and updated with future
+     * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
+     * as reference is valid.
+     */
+    public NetworkStatsCollection getOrLoadCompleteLocked() {
+        NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
+        if (complete == null) {
+            if (LOGD) Slog.d(TAG, "getOrLoadCompleteLocked() reading from disk for " + mCookie);
+            try {
+                complete = new NetworkStatsCollection(mBucketDuration);
+                mRotator.readMatching(complete, Long.MIN_VALUE, Long.MAX_VALUE);
+                complete.recordCollection(mPending);
+                mComplete = new WeakReference<NetworkStatsCollection>(complete);
+            } catch (IOException e) {
+                Log.wtf(TAG, "problem completely reading network stats", e);
+            }
+        }
+        return complete;
+    }
+
+    /**
+     * Record any delta that occurred since last {@link NetworkStats} snapshot,
+     * using the given {@link Map} to identify network interfaces. First
+     * snapshot is considered bootstrap, and is not counted as delta.
+     */
+    public void recordSnapshotLocked(NetworkStats snapshot,
+            Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) {
+        final HashSet<String> unknownIfaces = Sets.newHashSet();
+
+        // assume first snapshot is bootstrap and don't record
+        if (mLastSnapshot == null) {
+            mLastSnapshot = snapshot;
+            return;
+        }
+
+        final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
+
+        final NetworkStats delta = NetworkStats.subtract(
+                snapshot, mLastSnapshot, mObserver, mCookie);
+        final long end = currentTimeMillis;
+        final long start = end - delta.getElapsedRealtime();
+
+        NetworkStats.Entry entry = null;
+        for (int i = 0; i < delta.size(); i++) {
+            entry = delta.getValues(i, entry);
+            final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
+            if (ident == null) {
+                unknownIfaces.add(entry.iface);
+                continue;
+            }
+
+            // skip when no delta occured
+            if (entry.isEmpty()) continue;
+
+            // only record tag data when requested
+            if ((entry.tag == TAG_NONE) != mOnlyTags) {
+                mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+
+                // also record against boot stats when present
+                if (mSinceBoot != null) {
+                    mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+                }
+
+                // also record against complete dataset when present
+                if (complete != null) {
+                    complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+                }
+            }
+        }
+
+        mLastSnapshot = snapshot;
+
+        if (LOGV && unknownIfaces.size() > 0) {
+            Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
+        }
+    }
+
+    /**
+     * Consider persisting any pending deltas, if they are beyond
+     * {@link #mPersistThresholdBytes}.
+     */
+    public void maybePersistLocked(long currentTimeMillis) {
+        final long pendingBytes = mPending.getTotalBytes();
+        if (pendingBytes >= mPersistThresholdBytes) {
+            forcePersistLocked(currentTimeMillis);
+        } else {
+            mRotator.maybeRotate(currentTimeMillis);
+        }
+    }
+
+    /**
+     * Force persisting any pending deltas.
+     */
+    public void forcePersistLocked(long currentTimeMillis) {
+        if (mPending.isDirty()) {
+            if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
+            try {
+                mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
+                mRotator.maybeRotate(currentTimeMillis);
+                mPending.reset();
+            } catch (IOException e) {
+                Log.wtf(TAG, "problem persisting pending stats", e);
+            }
+        }
+    }
+
+    /**
+     * Remove the given UID from all {@link FileRotator} history, migrating it
+     * to {@link TrafficStats#UID_REMOVED}.
+     */
+    public void removeUidLocked(int uid) {
+        try {
+            // process all existing data to migrate uid
+            mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid));
+        } catch (IOException e) {
+            Log.wtf(TAG, "problem removing UID " + uid, e);
+        }
+
+        // clear UID from current stats snapshot
+        if (mLastSnapshot != null) {
+            mLastSnapshot = mLastSnapshot.withoutUid(uid);
+        }
+    }
+
+    /**
+     * Rewriter that will combine current {@link NetworkStatsCollection} values
+     * with anything read from disk, and write combined set to disk. Clears the
+     * original {@link NetworkStatsCollection} when finished writing.
+     */
+    private static class CombiningRewriter implements FileRotator.Rewriter {
+        private final NetworkStatsCollection mCollection;
+
+        public CombiningRewriter(NetworkStatsCollection collection) {
+            mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
+        }
+
+        /** {@inheritDoc} */
+        public void reset() {
+            // ignored
+        }
+
+        /** {@inheritDoc} */
+        public void read(InputStream in) throws IOException {
+            mCollection.read(in);
+        }
+
+        /** {@inheritDoc} */
+        public boolean shouldWrite() {
+            return true;
+        }
+
+        /** {@inheritDoc} */
+        public void write(OutputStream out) throws IOException {
+            mCollection.write(new DataOutputStream(out));
+            mCollection.reset();
+        }
+    }
+
+    /**
+     * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
+     * the requested UID, only writing data back when modified.
+     */
+    public static class RemoveUidRewriter implements FileRotator.Rewriter {
+        private final NetworkStatsCollection mTemp;
+        private final int mUid;
+
+        public RemoveUidRewriter(long bucketDuration, int uid) {
+            mTemp = new NetworkStatsCollection(bucketDuration);
+            mUid = uid;
+        }
+
+        /** {@inheritDoc} */
+        public void reset() {
+            mTemp.reset();
+        }
+
+        /** {@inheritDoc} */
+        public void read(InputStream in) throws IOException {
+            mTemp.read(in);
+            mTemp.clearDirty();
+            mTemp.removeUid(mUid);
+        }
+
+        /** {@inheritDoc} */
+        public boolean shouldWrite() {
+            return mTemp.isDirty();
+        }
+
+        /** {@inheritDoc} */
+        public void write(OutputStream out) throws IOException {
+            mTemp.write(new DataOutputStream(out));
+        }
+    }
+
+    public void importLegacyNetworkLocked(File file) throws IOException {
+        // legacy file still exists; start empty to avoid double importing
+        mRotator.deleteAll();
+
+        final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
+        collection.readLegacyNetwork(file);
+
+        final long startMillis = collection.getStartMillis();
+        final long endMillis = collection.getEndMillis();
+
+        if (!collection.isEmpty()) {
+            // process legacy data, creating active file at starting time, then
+            // using end time to possibly trigger rotation.
+            mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
+            mRotator.maybeRotate(endMillis);
+        }
+    }
+
+    public void importLegacyUidLocked(File file) throws IOException {
+        // legacy file still exists; start empty to avoid double importing
+        mRotator.deleteAll();
+
+        final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
+        collection.readLegacyUid(file, mOnlyTags);
+
+        final long startMillis = collection.getStartMillis();
+        final long endMillis = collection.getEndMillis();
+
+        if (!collection.isEmpty()) {
+            // process legacy data, creating active file at starting time, then
+            // using end time to possibly trigger rotation.
+            mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
+            mRotator.maybeRotate(endMillis);
+        }
+    }
+
+    public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
+        pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
+        if (fullHistory) {
+            pw.println("Complete history:");
+            getOrLoadCompleteLocked().dump(pw);
+        } else {
+            pw.println("History since boot:");
+            mSinceBoot.dump(pw);
+        }
+    }
+}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index eeb7fec..13c0640 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -34,14 +34,19 @@
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.NetworkTemplate.buildTemplateWifi;
-import static android.net.TrafficStats.UID_REMOVED;
-import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
-import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
-import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
+import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION;
+import static android.provider.Settings.Secure.NETSTATS_DEV_DELETE_AGE;
+import static android.provider.Settings.Secure.NETSTATS_DEV_PERSIST_BYTES;
+import static android.provider.Settings.Secure.NETSTATS_DEV_ROTATE_AGE;
+import static android.provider.Settings.Secure.NETSTATS_GLOBAL_ALERT_BYTES;
 import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
-import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY;
+import static android.provider.Settings.Secure.NETSTATS_SAMPLE_ENABLED;
+import static android.provider.Settings.Secure.NETSTATS_TIME_CACHE_MAX_AGE;
 import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
-import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
+import static android.provider.Settings.Secure.NETSTATS_UID_DELETE_AGE;
+import static android.provider.Settings.Secure.NETSTATS_UID_PERSIST_BYTES;
+import static android.provider.Settings.Secure.NETSTATS_UID_ROTATE_AGE;
 import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
 import static android.telephony.PhoneStateListener.LISTEN_NONE;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
@@ -61,12 +66,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkStatsService;
+import android.net.LinkProperties;
 import android.net.NetworkIdentity;
 import android.net.NetworkInfo;
 import android.net.NetworkState;
@@ -74,6 +77,7 @@
 import android.net.NetworkStats.NonMonotonicObserver;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
+import android.net.TrafficStats;
 import android.os.Binder;
 import android.os.DropBoxManager;
 import android.os.Environment;
@@ -94,32 +98,18 @@
 import android.util.SparseIntArray;
 import android.util.TrustedTime;
 
-import com.android.internal.os.AtomicFile;
-import com.android.internal.util.Objects;
+import com.android.internal.util.FileRotator;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.EventLogTags;
 import com.android.server.connectivity.Tethering;
-import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
-import com.google.android.collect.Sets;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.net.ProtocolException;
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Random;
-
-import libcore.io.IoUtils;
 
 /**
  * Collect and persist detailed network statistics, and provide this data to
@@ -127,19 +117,11 @@
  */
 public class NetworkStatsService extends INetworkStatsService.Stub {
     private static final String TAG = "NetworkStats";
-    private static final boolean LOGD = false;
     private static final boolean LOGV = false;
 
-    /** File header magic number: "ANET" */
-    private static final int FILE_MAGIC = 0x414E4554;
-    private static final int VERSION_NETWORK_INIT = 1;
-    private static final int VERSION_UID_INIT = 1;
-    private static final int VERSION_UID_WITH_IDENT = 2;
-    private static final int VERSION_UID_WITH_TAG = 3;
-    private static final int VERSION_UID_WITH_SET = 4;
-
     private static final int MSG_PERFORM_POLL = 1;
     private static final int MSG_UPDATE_IFACES = 2;
+    private static final int MSG_REGISTER_GLOBAL_ALERT = 3;
 
     /** Flags to control detail level of poll event. */
     private static final int FLAG_PERSIST_NETWORK = 0x1;
@@ -147,9 +129,6 @@
     private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
     private static final int FLAG_PERSIST_FORCE = 0x100;
 
-    /** Sample recent usage after each poll event. */
-    private static final boolean ENABLE_SAMPLE_AFTER_POLL = true;
-
     private static final String TAG_NETSTATS_ERROR = "netstats_error";
 
     private final Context mContext;
@@ -159,10 +138,12 @@
     private final TelephonyManager mTeleManager;
     private final NetworkStatsSettings mSettings;
 
+    private final File mSystemDir;
+    private final File mBaseDir;
+
     private final PowerManager.WakeLock mWakeLock;
 
     private IConnectivityManager mConnManager;
-    private DropBoxManager mDropBox;
 
     // @VisibleForTesting
     public static final String ACTION_NETWORK_STATS_POLL =
@@ -172,71 +153,72 @@
 
     private PendingIntent mPollIntent;
 
-    // TODO: trim empty history objects entirely
-
-    private static final long KB_IN_BYTES = 1024;
-    private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
-    private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES;
+    private static final String PREFIX_DEV = "dev";
+    private static final String PREFIX_UID = "uid";
+    private static final String PREFIX_UID_TAG = "uid_tag";
 
     /**
      * Settings that can be changed externally.
      */
     public interface NetworkStatsSettings {
         public long getPollInterval();
-        public long getPersistThreshold();
-        public long getNetworkBucketDuration();
-        public long getNetworkMaxHistory();
-        public long getUidBucketDuration();
-        public long getUidMaxHistory();
-        public long getTagMaxHistory();
         public long getTimeCacheMaxAge();
+        public long getGlobalAlertBytes();
+        public boolean getSampleEnabled();
+
+        public static class Config {
+            public final long bucketDuration;
+            public final long persistBytes;
+            public final long rotateAgeMillis;
+            public final long deleteAgeMillis;
+
+            public Config(long bucketDuration, long persistBytes, long rotateAgeMillis,
+                    long deleteAgeMillis) {
+                this.bucketDuration = bucketDuration;
+                this.persistBytes = persistBytes;
+                this.rotateAgeMillis = rotateAgeMillis;
+                this.deleteAgeMillis = deleteAgeMillis;
+            }
+        }
+
+        public Config getDevConfig();
+        public Config getUidConfig();
+        public Config getUidTagConfig();
     }
 
     private final Object mStatsLock = new Object();
 
     /** Set of currently active ifaces. */
     private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
-    /** Set of historical {@code dev} stats for known networks. */
-    private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkDevStats = Maps.newHashMap();
-    /** Set of historical {@code xtables} stats for known networks. */
-    private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkXtStats = Maps.newHashMap();
-    /** Set of historical {@code xtables} stats for known UIDs. */
-    private HashMap<UidStatsKey, NetworkStatsHistory> mUidStats = Maps.newHashMap();
+    /** Current default active iface. */
+    private String mActiveIface;
 
-    /** Flag if {@link #mNetworkDevStats} have been loaded from disk. */
-    private boolean mNetworkStatsLoaded = false;
-    /** Flag if {@link #mUidStats} have been loaded from disk. */
-    private boolean mUidStatsLoaded = false;
+    private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
+            new DropBoxNonMonotonicObserver();
 
-    private NetworkStats mLastPollNetworkDevSnapshot;
-    private NetworkStats mLastPollNetworkXtSnapshot;
-    private NetworkStats mLastPollUidSnapshot;
-    private NetworkStats mLastPollOperationsSnapshot;
+    private NetworkStatsRecorder mDevRecorder;
+    private NetworkStatsRecorder mUidRecorder;
+    private NetworkStatsRecorder mUidTagRecorder;
 
-    private NetworkStats mLastPersistNetworkDevSnapshot;
-    private NetworkStats mLastPersistNetworkXtSnapshot;
-    private NetworkStats mLastPersistUidSnapshot;
+    /** Cached {@link #mDevRecorder} stats. */
+    private NetworkStatsCollection mDevStatsCached;
 
     /** Current counter sets for each UID. */
     private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
 
     /** Data layer operation counters for splicing into other structures. */
-    private NetworkStats mOperations = new NetworkStats(0L, 10);
+    private NetworkStats mUidOperations = new NetworkStats(0L, 10);
 
     private final HandlerThread mHandlerThread;
     private final Handler mHandler;
 
-    private final AtomicFile mNetworkDevFile;
-    private final AtomicFile mNetworkXtFile;
-    private final AtomicFile mUidFile;
-
     public NetworkStatsService(
             Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
         this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
-                getSystemDir(), new DefaultNetworkStatsSettings(context));
+                getDefaultSystemDir(), new DefaultNetworkStatsSettings(context));
     }
 
-    private static File getSystemDir() {
+    private static File getDefaultSystemDir() {
         return new File(Environment.getDataDirectory(), "system");
     }
 
@@ -258,9 +240,9 @@
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
 
-        mNetworkDevFile = new AtomicFile(new File(systemDir, "netstats.bin"));
-        mNetworkXtFile = new AtomicFile(new File(systemDir, "netstats_xt.bin"));
-        mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin"));
+        mSystemDir = checkNotNull(systemDir);
+        mBaseDir = new File(systemDir, "netstats");
+        mBaseDir.mkdirs();
     }
 
     public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -273,17 +255,22 @@
             return;
         }
 
-        synchronized (mStatsLock) {
-            // read historical network stats from disk, since policy service
-            // might need them right away. we delay loading detailed UID stats
-            // until actually needed.
-            readNetworkDevStatsLocked();
-            readNetworkXtStatsLocked();
-            mNetworkStatsLoaded = true;
-        }
+        // create data recorders along with historical rotators
+        mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false);
+        mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false);
+        mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true);
 
-        // bootstrap initial stats to prevent double-counting later
-        bootstrapStats();
+        synchronized (mStatsLock) {
+            // upgrade any legacy stats, migrating them to rotated files
+            maybeUpgradeLegacyStatsLocked();
+
+            // read historical network stats from disk, since policy service
+            // might need them right away.
+            mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked();
+
+            // bootstrap initial stats to prevent double-counting later
+            bootstrapStatsLocked();
+        }
 
         // watch for network interfaces to be claimed
         final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
@@ -317,8 +304,14 @@
 
         registerPollAlarmLocked();
         registerGlobalAlert();
+    }
 
-        mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
+    private NetworkStatsRecorder buildRecorder(
+            String prefix, NetworkStatsSettings.Config config, boolean includeTags) {
+        return new NetworkStatsRecorder(
+                new FileRotator(mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
+                mNonMonotonicObserver, prefix, config.bucketDuration, config.persistBytes,
+                includeTags);
     }
 
     private void shutdownLocked() {
@@ -330,18 +323,44 @@
 
         mTeleManager.listen(mPhoneListener, LISTEN_NONE);
 
-        if (mNetworkStatsLoaded) {
-            writeNetworkDevStatsLocked();
-            writeNetworkXtStatsLocked();
+        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
+                : System.currentTimeMillis();
+
+        // persist any pending stats
+        mDevRecorder.forcePersistLocked(currentTime);
+        mUidRecorder.forcePersistLocked(currentTime);
+        mUidTagRecorder.forcePersistLocked(currentTime);
+
+        mDevRecorder = null;
+        mUidRecorder = null;
+        mUidTagRecorder = null;
+
+        mDevStatsCached = null;
+    }
+
+    private void maybeUpgradeLegacyStatsLocked() {
+        File file;
+        try {
+            file = new File(mSystemDir, "netstats.bin");
+            if (file.exists()) {
+                mDevRecorder.importLegacyNetworkLocked(file);
+                file.delete();
+            }
+
+            file = new File(mSystemDir, "netstats_xt.bin");
+            if (file.exists()) {
+                file.delete();
+            }
+
+            file = new File(mSystemDir, "netstats_uid.bin");
+            if (file.exists()) {
+                mUidRecorder.importLegacyUidLocked(file);
+                mUidTagRecorder.importLegacyUidLocked(file);
+                file.delete();
+            }
+        } catch (IOException e) {
+            Log.wtf(TAG, "problem during legacy upgrade", e);
         }
-        if (mUidStatsLoaded) {
-            writeUidStatsLocked();
-        }
-        mNetworkDevStats.clear();
-        mNetworkXtStats.clear();
-        mUidStats.clear();
-        mNetworkStatsLoaded = false;
-        mUidStatsLoaded = false;
     }
 
     /**
@@ -372,7 +391,7 @@
      */
     private void registerGlobalAlert() {
         try {
-            final long alertBytes = mSettings.getPersistThreshold();
+            final long alertBytes = mSettings.getGlobalAlertBytes();
             mNetworkManager.setGlobalAlert(alertBytes);
         } catch (IllegalStateException e) {
             Slog.w(TAG, "problem registering for global alert: " + e);
@@ -383,161 +402,39 @@
 
     @Override
     public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
-        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
-        return getHistoryForNetworkDev(template, fields);
+        return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
     }
 
-    private NetworkStatsHistory getHistoryForNetworkDev(NetworkTemplate template, int fields) {
-        return getHistoryForNetwork(template, fields, mNetworkDevStats);
-    }
-
-    private NetworkStatsHistory getHistoryForNetworkXt(NetworkTemplate template, int fields) {
-        return getHistoryForNetwork(template, fields, mNetworkXtStats);
-    }
-
-    private NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields,
-            HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
-        synchronized (mStatsLock) {
-            // combine all interfaces that match template
-            final NetworkStatsHistory combined = new NetworkStatsHistory(
-                    mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields);
-            for (NetworkIdentitySet ident : source.keySet()) {
-                if (templateMatches(template, ident)) {
-                    final NetworkStatsHistory history = source.get(ident);
-                    if (history != null) {
-                        combined.recordEntireHistory(history);
-                    }
-                }
-            }
-            return combined;
-        }
+    @Override
+    public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
+        return mDevStatsCached.getSummary(template, start, end);
     }
 
     @Override
     public NetworkStatsHistory getHistoryForUid(
             NetworkTemplate template, int uid, int set, int tag, int fields) {
-        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
-
-        synchronized (mStatsLock) {
-            ensureUidStatsLoadedLocked();
-
-            // combine all interfaces that match template
-            final NetworkStatsHistory combined = new NetworkStatsHistory(
-                    mSettings.getUidBucketDuration(), estimateUidBuckets(), fields);
-            for (UidStatsKey key : mUidStats.keySet()) {
-                final boolean setMatches = set == SET_ALL || key.set == set;
-                if (templateMatches(template, key.ident) && key.uid == uid && setMatches
-                        && key.tag == tag) {
-                    final NetworkStatsHistory history = mUidStats.get(key);
-                    combined.recordEntireHistory(history);
-                }
-            }
-
-            return combined;
+        // TODO: transition to stats sessions to avoid WeakReferences
+        if (tag == TAG_NONE) {
+            return mUidRecorder.getOrLoadCompleteLocked().getHistory(
+                    template, uid, set, tag, fields);
+        } else {
+            return mUidTagRecorder.getOrLoadCompleteLocked().getHistory(
+                    template, uid, set, tag, fields);
         }
     }
 
     @Override
-    public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
-        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
-        return getSummaryForNetworkDev(template, start, end);
-    }
-
-    private NetworkStats getSummaryForNetworkDev(NetworkTemplate template, long start, long end) {
-        return getSummaryForNetwork(template, start, end, mNetworkDevStats);
-    }
-
-    private NetworkStats getSummaryForNetworkXt(NetworkTemplate template, long start, long end) {
-        return getSummaryForNetwork(template, start, end, mNetworkXtStats);
-    }
-
-    private NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end,
-            HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
-        synchronized (mStatsLock) {
-            // use system clock to be externally consistent
-            final long now = System.currentTimeMillis();
-
-            final NetworkStats stats = new NetworkStats(end - start, 1);
-            final NetworkStats.Entry entry = new NetworkStats.Entry();
-            NetworkStatsHistory.Entry historyEntry = null;
-
-            // combine total from all interfaces that match template
-            for (NetworkIdentitySet ident : source.keySet()) {
-                if (templateMatches(template, ident)) {
-                    final NetworkStatsHistory history = source.get(ident);
-                    historyEntry = history.getValues(start, end, now, historyEntry);
-
-                    entry.iface = IFACE_ALL;
-                    entry.uid = UID_ALL;
-                    entry.tag = TAG_NONE;
-                    entry.rxBytes = historyEntry.rxBytes;
-                    entry.rxPackets = historyEntry.rxPackets;
-                    entry.txBytes = historyEntry.txBytes;
-                    entry.txPackets = historyEntry.txPackets;
-
-                    stats.combineValues(entry);
-                }
-            }
-
-            return stats;
-        }
-    }
-
-    private long getHistoryStartLocked(
-            NetworkTemplate template, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
-        long start = Long.MAX_VALUE;
-        for (NetworkIdentitySet ident : source.keySet()) {
-            if (templateMatches(template, ident)) {
-                final NetworkStatsHistory history = source.get(ident);
-                start = Math.min(start, history.getStart());
-            }
-        }
-        return start;
-    }
-
-    @Override
     public NetworkStats getSummaryForAllUid(
             NetworkTemplate template, long start, long end, boolean includeTags) {
-        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
-
-        synchronized (mStatsLock) {
-            ensureUidStatsLoadedLocked();
-
-            // use system clock to be externally consistent
-            final long now = System.currentTimeMillis();
-
-            final NetworkStats stats = new NetworkStats(end - start, 24);
-            final NetworkStats.Entry entry = new NetworkStats.Entry();
-            NetworkStatsHistory.Entry historyEntry = null;
-
-            for (UidStatsKey key : mUidStats.keySet()) {
-                if (templateMatches(template, key.ident)) {
-                    // always include summary under TAG_NONE, and include
-                    // other tags when requested.
-                    if (key.tag == TAG_NONE || includeTags) {
-                        final NetworkStatsHistory history = mUidStats.get(key);
-                        historyEntry = history.getValues(start, end, now, historyEntry);
-
-                        entry.iface = IFACE_ALL;
-                        entry.uid = key.uid;
-                        entry.set = key.set;
-                        entry.tag = key.tag;
-                        entry.rxBytes = historyEntry.rxBytes;
-                        entry.rxPackets = historyEntry.rxPackets;
-                        entry.txBytes = historyEntry.txBytes;
-                        entry.txPackets = historyEntry.txPackets;
-                        entry.operations = historyEntry.operations;
-
-                        if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
-                                || entry.txPackets > 0 || entry.operations > 0) {
-                            stats.combineValues(entry);
-                        }
-                    }
-                }
-            }
-
-            return stats;
+        // TODO: transition to stats sessions to avoid WeakReferences
+        final NetworkStats stats = mUidRecorder.getOrLoadCompleteLocked().getSummary(
+                template, start, end);
+        if (includeTags) {
+            final NetworkStats tagStats = mUidTagRecorder.getOrLoadCompleteLocked().getSummary(
+                    template, start, end);
+            stats.combineAllValues(tagStats);
         }
+        return stats;
     }
 
     @Override
@@ -567,7 +464,7 @@
         }
 
         // splice in operation counts
-        dataLayer.spliceOperationsFrom(mOperations);
+        dataLayer.spliceOperationsFrom(mUidOperations);
         return dataLayer;
     }
 
@@ -586,8 +483,10 @@
 
         synchronized (mStatsLock) {
             final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT);
-            mOperations.combineValues(IFACE_ALL, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
-            mOperations.combineValues(IFACE_ALL, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
+            mUidOperations.combineValues(
+                    mActiveIface, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
+            mUidOperations.combineValues(
+                    mActiveIface, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
         }
     }
 
@@ -608,7 +507,13 @@
     @Override
     public void forceUpdate() {
         mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
-        performPoll(FLAG_PERSIST_ALL);
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            performPoll(FLAG_PERSIST_ALL);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     /**
@@ -692,7 +597,7 @@
                 mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
 
                 // re-arm global alert for next update
-                registerGlobalAlert();
+                mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget();
             }
         }
     };
@@ -755,13 +660,17 @@
         performPollLocked(FLAG_PERSIST_NETWORK);
 
         final NetworkState[] states;
+        final LinkProperties activeLink;
         try {
             states = mConnManager.getAllNetworkState();
+            activeLink = mConnManager.getActiveLinkProperties();
         } catch (RemoteException e) {
             // ignored; service lives in system_server
             return;
         }
 
+        mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null;
+
         // rebuild active interfaces based on connected networks
         mActiveIfaces.clear();
 
@@ -785,12 +694,20 @@
      * Bootstrap initial stats snapshot, usually during {@link #systemReady()}
      * so we have baseline values without double-counting.
      */
-    private void bootstrapStats() {
+    private void bootstrapStatsLocked() {
+        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
+                : System.currentTimeMillis();
+
         try {
-            mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
-            mLastPollNetworkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
-            mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
-            mLastPollOperationsSnapshot = new NetworkStats(0L, 0);
+            // snapshot and record current counters; read UID stats first to
+            // avoid overcounting dev stats.
+            final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
+            final NetworkStats devSnapshot = getNetworkStatsSummary();
+
+            mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
+            mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
+            mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
+
         } catch (IllegalStateException e) {
             Slog.w(TAG, "problem reading network stats: " + e);
         } catch (RemoteException e) {
@@ -830,27 +747,16 @@
         // TODO: consider marking "untrusted" times in historical stats
         final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
                 : System.currentTimeMillis();
-        final long threshold = mSettings.getPersistThreshold();
 
-        final NetworkStats uidSnapshot;
-        final NetworkStats networkXtSnapshot;
-        final NetworkStats networkDevSnapshot;
         try {
-            // collect any tethering stats
-            final NetworkStats tetherSnapshot = getNetworkStatsTethering();
+            // snapshot and record current counters; read UID stats first to
+            // avoid overcounting dev stats.
+            final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
+            final NetworkStats devSnapshot = getNetworkStatsSummary();
 
-            // record uid stats, folding in tethering stats
-            uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
-            uidSnapshot.combineAllValues(tetherSnapshot);
-            performUidPollLocked(uidSnapshot, currentTime);
-
-            // record dev network stats
-            networkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
-            performNetworkDevPollLocked(networkDevSnapshot, currentTime);
-
-            // record xt network stats
-            networkXtSnapshot = computeNetworkXtSnapshotFromUid(uidSnapshot);
-            performNetworkXtPollLocked(networkXtSnapshot, currentTime);
+            mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
+            mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
+            mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
 
         } catch (IllegalStateException e) {
             Log.wtf(TAG, "problem reading network stats", e);
@@ -860,26 +766,19 @@
             return;
         }
 
-        // persist when enough network data has occurred
-        final long persistNetworkDevDelta = computeStatsDelta(
-                mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, "devp").getTotalBytes();
-        final long persistNetworkXtDelta = computeStatsDelta(
-                mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, "xtp").getTotalBytes();
-        final boolean networkOverThreshold = persistNetworkDevDelta > threshold
-                || persistNetworkXtDelta > threshold;
-        if (persistForce || (persistNetwork && networkOverThreshold)) {
-            writeNetworkDevStatsLocked();
-            writeNetworkXtStatsLocked();
-            mLastPersistNetworkDevSnapshot = networkDevSnapshot;
-            mLastPersistNetworkXtSnapshot = networkXtSnapshot;
-        }
-
-        // persist when enough uid data has occurred
-        final long persistUidDelta = computeStatsDelta(
-                mLastPersistUidSnapshot, uidSnapshot, true, "uidp").getTotalBytes();
-        if (persistForce || (persistUid && persistUidDelta > threshold)) {
-            writeUidStatsLocked();
-            mLastPersistUidSnapshot = uidSnapshot;
+        // persist any pending data depending on requested flags
+        if (persistForce) {
+            mDevRecorder.forcePersistLocked(currentTime);
+            mUidRecorder.forcePersistLocked(currentTime);
+            mUidTagRecorder.forcePersistLocked(currentTime);
+        } else {
+            if (persistNetwork) {
+                mDevRecorder.maybePersistLocked(currentTime);
+            }
+            if (persistUid) {
+                mUidRecorder.maybePersistLocked(currentTime);
+                mUidTagRecorder.maybePersistLocked(currentTime);
+            }
         }
 
         if (LOGV) {
@@ -887,9 +786,9 @@
             Slog.v(TAG, "performPollLocked() took " + duration + "ms");
         }
 
-        if (ENABLE_SAMPLE_AFTER_POLL) {
+        if (mSettings.getSampleEnabled()) {
             // sample stats after each full poll
-            performSample();
+            performSampleLocked();
         }
 
         // finally, dispatch updated event to any listeners
@@ -899,511 +798,58 @@
     }
 
     /**
-     * Update {@link #mNetworkDevStats} historical usage.
-     */
-    private void performNetworkDevPollLocked(NetworkStats networkDevSnapshot, long currentTime) {
-        final HashSet<String> unknownIface = Sets.newHashSet();
-
-        final NetworkStats delta = computeStatsDelta(
-                mLastPollNetworkDevSnapshot, networkDevSnapshot, false, "dev");
-        final long timeStart = currentTime - delta.getElapsedRealtime();
-
-        NetworkStats.Entry entry = null;
-        for (int i = 0; i < delta.size(); i++) {
-            entry = delta.getValues(i, entry);
-            final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
-            if (ident == null) {
-                unknownIface.add(entry.iface);
-                continue;
-            }
-
-            final NetworkStatsHistory history = findOrCreateNetworkDevStatsLocked(ident);
-            history.recordData(timeStart, currentTime, entry);
-        }
-
-        mLastPollNetworkDevSnapshot = networkDevSnapshot;
-
-        if (LOGD && unknownIface.size() > 0) {
-            Slog.w(TAG, "unknown dev interfaces " + unknownIface + ", ignoring those stats");
-        }
-    }
-
-    /**
-     * Update {@link #mNetworkXtStats} historical usage.
-     */
-    private void performNetworkXtPollLocked(NetworkStats networkXtSnapshot, long currentTime) {
-        final HashSet<String> unknownIface = Sets.newHashSet();
-
-        final NetworkStats delta = computeStatsDelta(
-                mLastPollNetworkXtSnapshot, networkXtSnapshot, false, "xt");
-        final long timeStart = currentTime - delta.getElapsedRealtime();
-
-        NetworkStats.Entry entry = null;
-        for (int i = 0; i < delta.size(); i++) {
-            entry = delta.getValues(i, entry);
-            final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
-            if (ident == null) {
-                unknownIface.add(entry.iface);
-                continue;
-            }
-
-            final NetworkStatsHistory history = findOrCreateNetworkXtStatsLocked(ident);
-            history.recordData(timeStart, currentTime, entry);
-        }
-
-        mLastPollNetworkXtSnapshot = networkXtSnapshot;
-
-        if (LOGD && unknownIface.size() > 0) {
-            Slog.w(TAG, "unknown xt interfaces " + unknownIface + ", ignoring those stats");
-        }
-    }
-
-    /**
-     * Update {@link #mUidStats} historical usage.
-     */
-    private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
-        ensureUidStatsLoadedLocked();
-
-        final NetworkStats delta = computeStatsDelta(
-                mLastPollUidSnapshot, uidSnapshot, false, "uid");
-        final NetworkStats operationsDelta = computeStatsDelta(
-                mLastPollOperationsSnapshot, mOperations, false, "uidop");
-        final long timeStart = currentTime - delta.getElapsedRealtime();
-
-        NetworkStats.Entry entry = null;
-        NetworkStats.Entry operationsEntry = null;
-        for (int i = 0; i < delta.size(); i++) {
-            entry = delta.getValues(i, entry);
-            final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
-            if (ident == null) {
-                if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
-                        || entry.txPackets > 0) {
-                    Log.w(TAG, "dropping UID delta from unknown iface: " + entry);
-                }
-                continue;
-            }
-
-            // splice in operation counts since last poll
-            final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.set, entry.tag);
-            if (j != -1) {
-                operationsEntry = operationsDelta.getValues(j, operationsEntry);
-                entry.operations = operationsEntry.operations;
-            }
-
-            final NetworkStatsHistory history = findOrCreateUidStatsLocked(
-                    ident, entry.uid, entry.set, entry.tag);
-            history.recordData(timeStart, currentTime, entry);
-        }
-
-        mLastPollUidSnapshot = uidSnapshot;
-        mLastPollOperationsSnapshot = mOperations.clone();
-    }
-
-    /**
      * Sample recent statistics summary into {@link EventLog}.
      */
-    private void performSample() {
-        final long largestBucketSize = Math.max(
-                mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration());
-
-        // take sample as atomic buckets
-        final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
-        final long end = now - (now % largestBucketSize) + largestBucketSize;
-        final long start = end - largestBucketSize;
-
+    private void performSampleLocked() {
+        // TODO: migrate trustedtime fixes to separate binary log events
         final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
-        long devHistoryStart = Long.MAX_VALUE;
 
-        NetworkTemplate template = null;
-        NetworkStats.Entry devTotal = null;
-        NetworkStats.Entry xtTotal = null;
-        NetworkStats.Entry uidTotal = null;
+        NetworkTemplate template;
+        NetworkStats.Entry devTotal;
+        NetworkStats.Entry xtTotal;
+        NetworkStats.Entry uidTotal;
 
         // collect mobile sample
         template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
-        devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
-        devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats);
-        xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
-        uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
+        devTotal = mDevRecorder.getTotalSinceBootLocked(template);
+        xtTotal = new NetworkStats.Entry();
+        uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
 
         EventLogTags.writeNetstatsMobileSample(
                 devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
                 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
                 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
-                trustedTime, devHistoryStart);
+                trustedTime);
 
         // collect wifi sample
         template = buildTemplateWifi();
-        devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
-        devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats);
-        xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
-        uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
+        devTotal = mDevRecorder.getTotalSinceBootLocked(template);
+        xtTotal = new NetworkStats.Entry();
+        uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
+
         EventLogTags.writeNetstatsWifiSample(
                 devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
                 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
                 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
-                trustedTime, devHistoryStart);
+                trustedTime);
     }
 
     /**
-     * Clean up {@link #mUidStats} after UID is removed.
+     * Clean up {@link #mUidRecorder} after UID is removed.
      */
     private void removeUidLocked(int uid) {
-        ensureUidStatsLoadedLocked();
-
         // perform one last poll before removing
         performPollLocked(FLAG_PERSIST_ALL);
 
-        final ArrayList<UidStatsKey> knownKeys = Lists.newArrayList();
-        knownKeys.addAll(mUidStats.keySet());
-
-        // migrate all UID stats into special "removed" bucket
-        for (UidStatsKey key : knownKeys) {
-            if (key.uid == uid) {
-                // only migrate combined TAG_NONE history
-                if (key.tag == TAG_NONE) {
-                    final NetworkStatsHistory uidHistory = mUidStats.get(key);
-                    final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked(
-                            key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
-                    removedHistory.recordEntireHistory(uidHistory);
-                }
-                mUidStats.remove(key);
-            }
-        }
-
-        // clear UID from current stats snapshot
-        if (mLastPollUidSnapshot != null) {
-            mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid);
-            mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
-        }
+        mUidRecorder.removeUidLocked(uid);
+        mUidTagRecorder.removeUidLocked(uid);
 
         // clear kernel stats associated with UID
         resetKernelUidStats(uid);
-
-        // since this was radical rewrite, push to disk
-        writeUidStatsLocked();
-    }
-
-    private NetworkStatsHistory findOrCreateNetworkXtStatsLocked(NetworkIdentitySet ident) {
-        return findOrCreateNetworkStatsLocked(ident, mNetworkXtStats);
-    }
-
-    private NetworkStatsHistory findOrCreateNetworkDevStatsLocked(NetworkIdentitySet ident) {
-        return findOrCreateNetworkStatsLocked(ident, mNetworkDevStats);
-    }
-
-    private NetworkStatsHistory findOrCreateNetworkStatsLocked(
-            NetworkIdentitySet ident, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
-        final NetworkStatsHistory existing = source.get(ident);
-
-        // update when no existing, or when bucket duration changed
-        final long bucketDuration = mSettings.getNetworkBucketDuration();
-        NetworkStatsHistory updated = null;
-        if (existing == null) {
-            updated = new NetworkStatsHistory(bucketDuration, 10);
-        } else if (existing.getBucketDuration() != bucketDuration) {
-            updated = new NetworkStatsHistory(
-                    bucketDuration, estimateResizeBuckets(existing, bucketDuration));
-            updated.recordEntireHistory(existing);
-        }
-
-        if (updated != null) {
-            source.put(ident, updated);
-            return updated;
-        } else {
-            return existing;
-        }
-    }
-
-    private NetworkStatsHistory findOrCreateUidStatsLocked(
-            NetworkIdentitySet ident, int uid, int set, int tag) {
-        ensureUidStatsLoadedLocked();
-
-        final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
-        final NetworkStatsHistory existing = mUidStats.get(key);
-
-        // update when no existing, or when bucket duration changed
-        final long bucketDuration = mSettings.getUidBucketDuration();
-        NetworkStatsHistory updated = null;
-        if (existing == null) {
-            updated = new NetworkStatsHistory(bucketDuration, 10);
-        } else if (existing.getBucketDuration() != bucketDuration) {
-            updated = new NetworkStatsHistory(
-                    bucketDuration, estimateResizeBuckets(existing, bucketDuration));
-            updated.recordEntireHistory(existing);
-        }
-
-        if (updated != null) {
-            mUidStats.put(key, updated);
-            return updated;
-        } else {
-            return existing;
-        }
-    }
-
-    private void readNetworkDevStatsLocked() {
-        if (LOGV) Slog.v(TAG, "readNetworkDevStatsLocked()");
-        readNetworkStats(mNetworkDevFile, mNetworkDevStats);
-    }
-
-    private void readNetworkXtStatsLocked() {
-        if (LOGV) Slog.v(TAG, "readNetworkXtStatsLocked()");
-        readNetworkStats(mNetworkXtFile, mNetworkXtStats);
-    }
-
-    private static void readNetworkStats(
-            AtomicFile inputFile, HashMap<NetworkIdentitySet, NetworkStatsHistory> output) {
-        // clear any existing stats and read from disk
-        output.clear();
-
-        DataInputStream in = null;
-        try {
-            in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
-
-            // verify file magic header intact
-            final int magic = in.readInt();
-            if (magic != FILE_MAGIC) {
-                throw new ProtocolException("unexpected magic: " + magic);
-            }
-
-            final int version = in.readInt();
-            switch (version) {
-                case VERSION_NETWORK_INIT: {
-                    // network := size *(NetworkIdentitySet NetworkStatsHistory)
-                    final int size = in.readInt();
-                    for (int i = 0; i < size; i++) {
-                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
-                        final NetworkStatsHistory history = new NetworkStatsHistory(in);
-                        output.put(ident, history);
-                    }
-                    break;
-                }
-                default: {
-                    throw new ProtocolException("unexpected version: " + version);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            // missing stats is okay, probably first boot
-        } catch (IOException e) {
-            Log.wtf(TAG, "problem reading network stats", e);
-        } finally {
-            IoUtils.closeQuietly(in);
-        }
-    }
-
-    private void ensureUidStatsLoadedLocked() {
-        if (!mUidStatsLoaded) {
-            readUidStatsLocked();
-            mUidStatsLoaded = true;
-        }
-    }
-
-    private void readUidStatsLocked() {
-        if (LOGV) Slog.v(TAG, "readUidStatsLocked()");
-
-        // clear any existing stats and read from disk
-        mUidStats.clear();
-
-        DataInputStream in = null;
-        try {
-            in = new DataInputStream(new BufferedInputStream(mUidFile.openRead()));
-
-            // verify file magic header intact
-            final int magic = in.readInt();
-            if (magic != FILE_MAGIC) {
-                throw new ProtocolException("unexpected magic: " + magic);
-            }
-
-            final int version = in.readInt();
-            switch (version) {
-                case VERSION_UID_INIT: {
-                    // uid := size *(UID NetworkStatsHistory)
-
-                    // drop this data version, since we don't have a good
-                    // mapping into NetworkIdentitySet.
-                    break;
-                }
-                case VERSION_UID_WITH_IDENT: {
-                    // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
-
-                    // drop this data version, since this version only existed
-                    // for a short time.
-                    break;
-                }
-                case VERSION_UID_WITH_TAG:
-                case VERSION_UID_WITH_SET: {
-                    // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
-                    final int identSize = in.readInt();
-                    for (int i = 0; i < identSize; i++) {
-                        final NetworkIdentitySet ident = new NetworkIdentitySet(in);
-
-                        final int size = in.readInt();
-                        for (int j = 0; j < size; j++) {
-                            final int uid = in.readInt();
-                            final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
-                                    : SET_DEFAULT;
-                            final int tag = in.readInt();
-
-                            final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
-                            final NetworkStatsHistory history = new NetworkStatsHistory(in);
-                            mUidStats.put(key, history);
-                        }
-                    }
-                    break;
-                }
-                default: {
-                    throw new ProtocolException("unexpected version: " + version);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            // missing stats is okay, probably first boot
-        } catch (IOException e) {
-            Log.wtf(TAG, "problem reading uid stats", e);
-        } finally {
-            IoUtils.closeQuietly(in);
-        }
-    }
-
-    private void writeNetworkDevStatsLocked() {
-        if (LOGV) Slog.v(TAG, "writeNetworkDevStatsLocked()");
-        writeNetworkStats(mNetworkDevStats, mNetworkDevFile);
-    }
-
-    private void writeNetworkXtStatsLocked() {
-        if (LOGV) Slog.v(TAG, "writeNetworkXtStatsLocked()");
-        writeNetworkStats(mNetworkXtStats, mNetworkXtFile);
-    }
-
-    private void writeNetworkStats(
-            HashMap<NetworkIdentitySet, NetworkStatsHistory> input, AtomicFile outputFile) {
-        // TODO: consider duplicating stats and releasing lock while writing
-
-        // trim any history beyond max
-        if (mTime.hasCache()) {
-            final long systemCurrentTime = System.currentTimeMillis();
-            final long trustedCurrentTime = mTime.currentTimeMillis();
-
-            final long currentTime = Math.min(systemCurrentTime, trustedCurrentTime);
-            final long maxHistory = mSettings.getNetworkMaxHistory();
-
-            for (NetworkStatsHistory history : input.values()) {
-                final int beforeSize = history.size();
-                history.removeBucketsBefore(currentTime - maxHistory);
-                final int afterSize = history.size();
-
-                if (beforeSize > 24 && afterSize < beforeSize / 2) {
-                    // yikes, dropping more than half of significant history
-                    final StringBuilder builder = new StringBuilder();
-                    builder.append("yikes, dropping more than half of history").append('\n');
-                    builder.append("systemCurrentTime=").append(systemCurrentTime).append('\n');
-                    builder.append("trustedCurrentTime=").append(trustedCurrentTime).append('\n');
-                    builder.append("maxHistory=").append(maxHistory).append('\n');
-                    builder.append("beforeSize=").append(beforeSize).append('\n');
-                    builder.append("afterSize=").append(afterSize).append('\n');
-                    mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
-                }
-            }
-        }
-
-        FileOutputStream fos = null;
-        try {
-            fos = outputFile.startWrite();
-            final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
-
-            out.writeInt(FILE_MAGIC);
-            out.writeInt(VERSION_NETWORK_INIT);
-
-            out.writeInt(input.size());
-            for (NetworkIdentitySet ident : input.keySet()) {
-                final NetworkStatsHistory history = input.get(ident);
-                ident.writeToStream(out);
-                history.writeToStream(out);
-            }
-
-            out.flush();
-            outputFile.finishWrite(fos);
-        } catch (IOException e) {
-            Log.wtf(TAG, "problem writing stats", e);
-            if (fos != null) {
-                outputFile.failWrite(fos);
-            }
-        }
-    }
-
-    private void writeUidStatsLocked() {
-        if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
-
-        if (!mUidStatsLoaded) {
-            Slog.w(TAG, "asked to write UID stats when not loaded; skipping");
-            return;
-        }
-
-        // TODO: consider duplicating stats and releasing lock while writing
-
-        // trim any history beyond max
-        if (mTime.hasCache()) {
-            final long currentTime = Math.min(
-                    System.currentTimeMillis(), mTime.currentTimeMillis());
-            final long maxUidHistory = mSettings.getUidMaxHistory();
-            final long maxTagHistory = mSettings.getTagMaxHistory();
-            for (UidStatsKey key : mUidStats.keySet()) {
-                final NetworkStatsHistory history = mUidStats.get(key);
-
-                // detailed tags are trimmed sooner than summary in TAG_NONE
-                if (key.tag == TAG_NONE) {
-                    history.removeBucketsBefore(currentTime - maxUidHistory);
-                } else {
-                    history.removeBucketsBefore(currentTime - maxTagHistory);
-                }
-            }
-        }
-
-        // build UidStatsKey lists grouped by ident
-        final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap();
-        for (UidStatsKey key : mUidStats.keySet()) {
-            ArrayList<UidStatsKey> keys = keysByIdent.get(key.ident);
-            if (keys == null) {
-                keys = Lists.newArrayList();
-                keysByIdent.put(key.ident, keys);
-            }
-            keys.add(key);
-        }
-
-        FileOutputStream fos = null;
-        try {
-            fos = mUidFile.startWrite();
-            final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
-
-            out.writeInt(FILE_MAGIC);
-            out.writeInt(VERSION_UID_WITH_SET);
-
-            out.writeInt(keysByIdent.size());
-            for (NetworkIdentitySet ident : keysByIdent.keySet()) {
-                final ArrayList<UidStatsKey> keys = keysByIdent.get(ident);
-                ident.writeToStream(out);
-
-                out.writeInt(keys.size());
-                for (UidStatsKey key : keys) {
-                    final NetworkStatsHistory history = mUidStats.get(key);
-                    out.writeInt(key.uid);
-                    out.writeInt(key.set);
-                    out.writeInt(key.tag);
-                    history.writeToStream(out);
-                }
-            }
-
-            out.flush();
-            mUidFile.finishWrite(fos);
-        } catch (IOException e) {
-            Log.wtf(TAG, "problem writing stats", e);
-            if (fos != null) {
-                mUidFile.failWrite(fos);
-            }
-        }
     }
 
     @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
 
         final HashSet<String> argSet = new HashSet<String>();
@@ -1411,187 +857,80 @@
             argSet.add(arg);
         }
 
-        final boolean fullHistory = argSet.contains("full");
+        // usage: dumpsys netstats --full --uid --tag --poll --checkin
+        final boolean poll = argSet.contains("--poll") || argSet.contains("poll");
+        final boolean checkin = argSet.contains("--checkin");
+        final boolean fullHistory = argSet.contains("--full") || argSet.contains("full");
+        final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail");
+        final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail");
+
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
 
         synchronized (mStatsLock) {
-            // TODO: remove this testing code, since it corrupts stats
-            if (argSet.contains("generate")) {
-                generateRandomLocked(args);
-                pw.println("Generated stub stats");
-                return;
-            }
-
-            if (argSet.contains("poll")) {
+            if (poll) {
                 performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
                 pw.println("Forced poll");
                 return;
             }
 
+            if (checkin) {
+                // list current stats files to verify rotation
+                pw.println("Current files:");
+                pw.increaseIndent();
+                for (String file : mBaseDir.list()) {
+                    pw.println(file);
+                }
+                pw.decreaseIndent();
+                return;
+            }
+
             pw.println("Active interfaces:");
+            pw.increaseIndent();
             for (String iface : mActiveIfaces.keySet()) {
                 final NetworkIdentitySet ident = mActiveIfaces.get(iface);
-                pw.print("  iface="); pw.print(iface);
+                pw.print("iface="); pw.print(iface);
                 pw.print(" ident="); pw.println(ident.toString());
             }
+            pw.decreaseIndent();
 
-            pw.println("Known historical dev stats:");
-            for (NetworkIdentitySet ident : mNetworkDevStats.keySet()) {
-                final NetworkStatsHistory history = mNetworkDevStats.get(ident);
-                pw.print("  ident="); pw.println(ident.toString());
-                history.dump("  ", pw, fullHistory);
+            pw.println("Dev stats:");
+            pw.increaseIndent();
+            mDevRecorder.dumpLocked(pw, fullHistory);
+            pw.decreaseIndent();
+
+            if (includeUid) {
+                pw.println("UID stats:");
+                pw.increaseIndent();
+                mUidRecorder.dumpLocked(pw, fullHistory);
+                pw.decreaseIndent();
             }
 
-            pw.println("Known historical xt stats:");
-            for (NetworkIdentitySet ident : mNetworkXtStats.keySet()) {
-                final NetworkStatsHistory history = mNetworkXtStats.get(ident);
-                pw.print("  ident="); pw.println(ident.toString());
-                history.dump("  ", pw, fullHistory);
-            }
-
-            if (argSet.contains("detail")) {
-                // since explicitly requested with argument, we're okay to load
-                // from disk if not already in memory.
-                ensureUidStatsLoadedLocked();
-
-                final ArrayList<UidStatsKey> keys = Lists.newArrayList();
-                keys.addAll(mUidStats.keySet());
-                Collections.sort(keys);
-
-                pw.println("Detailed UID stats:");
-                for (UidStatsKey key : keys) {
-                    pw.print("  ident="); pw.print(key.ident.toString());
-                    pw.print(" uid="); pw.print(key.uid);
-                    pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
-                    pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
-
-                    final NetworkStatsHistory history = mUidStats.get(key);
-                    history.dump("    ", pw, fullHistory);
-                }
+            if (includeTag) {
+                pw.println("UID tag stats:");
+                pw.increaseIndent();
+                mUidTagRecorder.dumpLocked(pw, fullHistory);
+                pw.decreaseIndent();
             }
         }
     }
 
+    private NetworkStats getNetworkStatsSummary() throws RemoteException {
+        return mNetworkManager.getNetworkStatsSummary();
+    }
+
     /**
-     * @deprecated only for temporary testing
+     * Return snapshot of current UID statistics, including any
+     * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values.
      */
-    @Deprecated
-    private void generateRandomLocked(String[] args) {
-        final long totalBytes = Long.parseLong(args[1]);
-        final long totalTime = Long.parseLong(args[2]);
-        
-        final PackageManager pm = mContext.getPackageManager();
-        final ArrayList<Integer> specialUidList = Lists.newArrayList();
-        for (int i = 3; i < args.length; i++) {
-            try {
-                specialUidList.add(pm.getApplicationInfo(args[i], 0).uid);
-            } catch (NameNotFoundException e) {
-                throw new RuntimeException(e);
-            }
-        }
+    private NetworkStats getNetworkStatsUidDetail() throws RemoteException {
+        final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
 
-        final HashSet<Integer> otherUidSet = Sets.newHashSet();
-        for (ApplicationInfo info : pm.getInstalledApplications(0)) {
-            if (pm.checkPermission(android.Manifest.permission.INTERNET, info.packageName)
-                    == PackageManager.PERMISSION_GRANTED && !specialUidList.contains(info.uid)) {
-                otherUidSet.add(info.uid);
-            }
-        }
+        // fold tethering stats and operations into uid snapshot
+        final NetworkStats tetherSnapshot = getNetworkStatsTethering();
+        uidSnapshot.combineAllValues(tetherSnapshot);
+        uidSnapshot.combineAllValues(mUidOperations);
 
-        final ArrayList<Integer> otherUidList = new ArrayList<Integer>(otherUidSet);
-
-        final long end = System.currentTimeMillis();
-        final long start = end - totalTime;
-
-        mNetworkDevStats.clear();
-        mNetworkXtStats.clear();
-        mUidStats.clear();
-
-        final Random r = new Random();
-        for (NetworkIdentitySet ident : mActiveIfaces.values()) {
-            final NetworkStatsHistory devHistory = findOrCreateNetworkDevStatsLocked(ident);
-            final NetworkStatsHistory xtHistory = findOrCreateNetworkXtStatsLocked(ident);
-
-            final ArrayList<Integer> uidList = new ArrayList<Integer>();
-            uidList.addAll(specialUidList);
-
-            if (uidList.size() == 0) {
-                Collections.shuffle(otherUidList);
-                uidList.addAll(otherUidList);
-            }
-
-            boolean first = true;
-            long remainingBytes = totalBytes;
-            for (int uid : uidList) {
-                final NetworkStatsHistory defaultHistory = findOrCreateUidStatsLocked(
-                        ident, uid, SET_DEFAULT, TAG_NONE);
-                final NetworkStatsHistory foregroundHistory = findOrCreateUidStatsLocked(
-                        ident, uid, SET_FOREGROUND, TAG_NONE);
-
-                final long uidBytes = totalBytes / uidList.size();
-
-                final float fractionDefault = r.nextFloat();
-                final long defaultBytes = (long) (uidBytes * fractionDefault);
-                final long foregroundBytes = (long) (uidBytes * (1 - fractionDefault));
-
-                defaultHistory.generateRandom(start, end, defaultBytes);
-                foregroundHistory.generateRandom(start, end, foregroundBytes);
-
-                if (first) {
-                    final long bumpTime = (start + end) / 2;
-                    defaultHistory.recordData(
-                            bumpTime, bumpTime + DAY_IN_MILLIS, 200 * MB_IN_BYTES, 0);
-                    first = false;
-                }
-
-                devHistory.recordEntireHistory(defaultHistory);
-                devHistory.recordEntireHistory(foregroundHistory);
-                xtHistory.recordEntireHistory(defaultHistory);
-                xtHistory.recordEntireHistory(foregroundHistory);
-            }
-        }
-    }
-
-    private StatsObserver mStatsObserver = new StatsObserver();
-
-    private class StatsObserver implements NonMonotonicObserver {
-        private String mCurrentType;
-
-        public void setCurrentType(String type) {
-            mCurrentType = type;
-        }
-
-        /** {@inheritDoc} */
-        public void foundNonMonotonic(
-                NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) {
-            Log.w(TAG, "found non-monotonic values; saving to dropbox");
-
-            // record error for debugging
-            final StringBuilder builder = new StringBuilder();
-            builder.append("found non-monotonic " + mCurrentType + " values at left[" + leftIndex
-                    + "] - right[" + rightIndex + "]\n");
-            builder.append("left=").append(left).append('\n');
-            builder.append("right=").append(right).append('\n');
-            mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
-        }
-    }
-
-    /**
-     * Return the delta between two {@link NetworkStats} snapshots, where {@code
-     * before} can be {@code null}.
-     */
-    private NetworkStats computeStatsDelta(
-            NetworkStats before, NetworkStats current, boolean collectStale, String type) {
-        if (before != null) {
-            mStatsObserver.setCurrentType(type);
-            return NetworkStats.subtract(current, before, mStatsObserver);
-        } else if (collectStale) {
-            // caller is okay collecting stale stats for first call.
-            return current;
-        } else {
-            // this is first snapshot; to prevent from double-counting we only
-            // observe traffic occuring between known snapshots.
-            return new NetworkStats(0L, 10);
-        }
+        return uidSnapshot;
     }
 
     /**
@@ -1608,35 +947,6 @@
         }
     }
 
-    private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) {
-        return uidSnapshot.groupedByIface();
-    }
-
-    private int estimateNetworkBuckets() {
-        return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration());
-    }
-
-    private int estimateUidBuckets() {
-        return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration());
-    }
-
-    private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) {
-        return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration);
-    }
-
-    /**
-     * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
-     * in the given {@link NetworkIdentitySet}.
-     */
-    private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
-        for (NetworkIdentity ident : identSet) {
-            if (template.matches(ident)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private Handler.Callback mHandlerCallback = new Handler.Callback() {
         /** {@inheritDoc} */
         public boolean handleMessage(Message msg) {
@@ -1650,6 +960,10 @@
                     updateIfaces();
                     return true;
                 }
+                case MSG_REGISTER_GLOBAL_ALERT: {
+                    registerGlobalAlert();
+                    return true;
+                }
                 default: {
                     return false;
                 }
@@ -1672,40 +986,22 @@
         }
     }
 
-    /**
-     * Key uniquely identifying a {@link NetworkStatsHistory} for a UID.
-     */
-    private static class UidStatsKey implements Comparable<UidStatsKey> {
-        public final NetworkIdentitySet ident;
-        public final int uid;
-        public final int set;
-        public final int tag;
-
-        public UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag) {
-            this.ident = ident;
-            this.uid = uid;
-            this.set = set;
-            this.tag = tag;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(ident, uid, set, tag);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof UidStatsKey) {
-                final UidStatsKey key = (UidStatsKey) obj;
-                return Objects.equal(ident, key.ident) && uid == key.uid && set == key.set
-                        && tag == key.tag;
-            }
-            return false;
-        }
-
+    private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> {
         /** {@inheritDoc} */
-        public int compareTo(UidStatsKey another) {
-            return Integer.compare(uid, another.uid);
+        public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
+                int rightIndex, String cookie) {
+            Log.w(TAG, "found non-monotonic values; saving to dropbox");
+
+            // record error for debugging
+            final StringBuilder builder = new StringBuilder();
+            builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex
+                    + "] - right[" + rightIndex + "]\n");
+            builder.append("left=").append(left).append('\n');
+            builder.append("right=").append(right).append('\n');
+
+            final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService(
+                    Context.DROPBOX_SERVICE);
+            dropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
         }
     }
 
@@ -1731,26 +1027,35 @@
         public long getPollInterval() {
             return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
         }
-        public long getPersistThreshold() {
-            return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 2 * MB_IN_BYTES);
-        }
-        public long getNetworkBucketDuration() {
-            return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS);
-        }
-        public long getNetworkMaxHistory() {
-            return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS);
-        }
-        public long getUidBucketDuration() {
-            return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
-        }
-        public long getUidMaxHistory() {
-            return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS);
-        }
-        public long getTagMaxHistory() {
-            return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS);
-        }
         public long getTimeCacheMaxAge() {
-            return DAY_IN_MILLIS;
+            return getSecureLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS);
+        }
+        public long getGlobalAlertBytes() {
+            return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, 2 * MB_IN_BYTES);
+        }
+        public boolean getSampleEnabled() {
+            return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true);
+        }
+
+        public Config getDevConfig() {
+            return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
+                    getSecureLong(NETSTATS_DEV_PERSIST_BYTES, 2 * MB_IN_BYTES),
+                    getSecureLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS),
+                    getSecureLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS));
+        }
+
+        public Config getUidConfig() {
+            return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
+                    getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES),
+                    getSecureLong(NETSTATS_UID_ROTATE_AGE, 15 * DAY_IN_MILLIS),
+                    getSecureLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS));
+        }
+
+        public Config getUidTagConfig() {
+            return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
+                    getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES),
+                    getSecureLong(NETSTATS_UID_ROTATE_AGE, 5 * DAY_IN_MILLIS),
+                    getSecureLong(NETSTATS_UID_DELETE_AGE, 15 * DAY_IN_MILLIS));
         }
     }
 }
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index 11ccd60..9b1973e 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -277,6 +277,27 @@
         return execute(builder.toString());
     }
 
+    /**
+     * Clone all the package data directories from srcUserId to targetUserId. If copyData is true,
+     * some of the data is also copied, otherwise just empty directories are created with the
+     * correct access rights.
+     * @param srcUserId user to copy the data directories from
+     * @param targetUserId user to copy the data directories to
+     * @param copyData whether the data itself is to be copied. If false, empty directories are
+     * created.
+     * @return success/error code
+     */
+    public int cloneUserData(int srcUserId, int targetUserId, boolean copyData) {
+        StringBuilder builder = new StringBuilder("cloneuserdata");
+        builder.append(' ');
+        builder.append(srcUserId);
+        builder.append(' ');
+        builder.append(targetUserId);
+        builder.append(' ');
+        builder.append(copyData ? '1' : '0');
+        return execute(builder.toString());
+    }
+
     public boolean ping() {
         if (execute("ping") < 0) {
             return false;
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 090ca64..7169015 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -92,6 +92,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserId;
 import android.security.SystemKeyStore;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -163,13 +164,9 @@
     private static final boolean DEBUG_APP_DIR_OBSERVER = false;
     private static final boolean DEBUG_VERIFY = false;
 
-    static final boolean MULTIPLE_APPLICATION_UIDS = true;
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
     private static final int NFC_UID = Process.NFC_UID;
-    static final int FIRST_APPLICATION_UID =
-        Process.FIRST_APPLICATION_UID;
-    static final int MAX_APPLICATION_UIDS = 1000;
 
     private static final boolean GET_CERTIFICATES = true;
 
@@ -873,18 +870,9 @@
         mSettings = new Settings();
         mSettings.addSharedUserLPw("android.uid.system",
                 Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
-        mSettings.addSharedUserLPw("android.uid.phone",
-                MULTIPLE_APPLICATION_UIDS
-                        ? RADIO_UID : FIRST_APPLICATION_UID,
-                ApplicationInfo.FLAG_SYSTEM);
-        mSettings.addSharedUserLPw("android.uid.log",
-                MULTIPLE_APPLICATION_UIDS
-                        ? LOG_UID : FIRST_APPLICATION_UID,
-                ApplicationInfo.FLAG_SYSTEM);
-        mSettings.addSharedUserLPw("android.uid.nfc",
-                MULTIPLE_APPLICATION_UIDS
-                        ? NFC_UID : FIRST_APPLICATION_UID,
-                ApplicationInfo.FLAG_SYSTEM);
+        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);
+        mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);
+        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);
 
         String separateProcesses = SystemProperties.get("debug.separate_processes");
         if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -1743,12 +1731,16 @@
     }
 
     public ActivityInfo getActivityInfo(ComponentName component, int flags) {
+        return getActivityInfo(component, flags, Binder.getOrigCallingUser());
+    }
+
+    ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
             if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
             if (a != null && mSettings.isEnabledLPr(a.info, flags)) {
-                return PackageParser.generateActivityInfo(a, flags);
+                return PackageParser.generateActivityInfo(a, flags, userId);
             }
             if (mResolveComponentName.equals(component)) {
                 return mResolveActivity;
@@ -1758,36 +1750,48 @@
     }
 
     public ActivityInfo getReceiverInfo(ComponentName component, int flags) {
+        return getReceiverInfo(component, flags, Binder.getOrigCallingUser());
+    }
+
+    ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getReceiverInfo " + component + ": " + a);
             if (a != null && mSettings.isEnabledLPr(a.info, flags)) {
-                return PackageParser.generateActivityInfo(a, flags);
+                return PackageParser.generateActivityInfo(a, flags, userId);
             }
         }
         return null;
     }
 
     public ServiceInfo getServiceInfo(ComponentName component, int flags) {
+        return getServiceInfo(component, flags, Binder.getOrigCallingUser());
+    }
+
+    ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getServiceInfo " + component + ": " + s);
             if (s != null && mSettings.isEnabledLPr(s.info, flags)) {
-                return PackageParser.generateServiceInfo(s, flags);
+                return PackageParser.generateServiceInfo(s, flags, userId);
             }
         }
         return null;
     }
 
     public ProviderInfo getProviderInfo(ComponentName component, int flags) {
+        return getProviderInfo(component, flags, UserId.getUserId(Binder.getCallingUid()));
+    }
+
+    ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
         synchronized (mPackages) {
             PackageParser.Provider p = mProvidersByComponent.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
                 TAG, "getProviderInfo " + component + ": " + p);
             if (p != null && mSettings.isEnabledLPr(p.info, flags)) {
-                return PackageParser.generateProviderInfo(p, flags);
+                return PackageParser.generateProviderInfo(p, flags, userId);
             }
         }
         return null;
@@ -1850,7 +1854,7 @@
 
     public int checkUidPermission(String permName, int uid) {
         synchronized (mPackages) {
-            Object obj = mSettings.getUserIdLPr(uid);
+            Object obj = mSettings.getUserIdLPr(UserId.getAppId(uid));
             if (obj != null) {
                 GrantedPermissions gp = (GrantedPermissions)obj;
                 if (gp.grantedPermissions.contains(permName)) {
@@ -1881,7 +1885,7 @@
         if (permName != null) {
             BasePermission bp = findPermissionTreeLP(permName);
             if (bp != null) {
-                if (bp.uid == Binder.getCallingUid()) {
+                if (bp.uid == UserId.getAppId(Binder.getCallingUid())) {
                     return bp;
                 }
                 throw new SecurityException("Calling uid "
@@ -2010,6 +2014,9 @@
     }
 
     public int checkUidSignatures(int uid1, int uid2) {
+        // Map to base uids.
+        uid1 = UserId.getAppId(uid1);
+        uid2 = UserId.getAppId(uid2);
         // reader
         synchronized (mPackages) {
             Signature[] s1;
@@ -2067,6 +2074,7 @@
     }
 
     public String[] getPackagesForUid(int uid) {
+        uid = UserId.getAppId(uid);
         // reader
         synchronized (mPackages) {
             Object obj = mSettings.getUserIdLPr(uid);
@@ -2091,7 +2099,7 @@
     public String getNameForUid(int uid) {
         // reader
         synchronized (mPackages) {
-            Object obj = mSettings.getUserIdLPr(uid);
+            Object obj = mSettings.getUserIdLPr(UserId.getAppId(uid));
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 return sus.name + ":" + sus.userId;
@@ -2110,7 +2118,7 @@
         // reader
         synchronized (mPackages) {
             final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, false);
-            if(suid == null) {
+            if (suid == null) {
                 return -1;
             }
             return suid.userId;
@@ -2252,6 +2260,7 @@
                 comp = intent.getComponent();
             }
         }
+
         if (comp != null) {
             final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
             final ActivityInfo ai = getActivityInfo(comp, flags);
@@ -2603,6 +2612,7 @@
             Arrays.sort(keys);
             int i = getContinuationPoint(keys, lastRead);
             final int N = keys.length;
+            final int userId = UserId.getUserId(Binder.getCallingUid());
 
             while (i < N) {
                 final String packageName = keys[i++];
@@ -2616,7 +2626,7 @@
                 } else {
                     final PackageParser.Package p = mPackages.get(packageName);
                     if (p != null) {
-                        ai = PackageParser.generateApplicationInfo(p, flags);
+                        ai = PackageParser.generateApplicationInfo(p, flags, userId);
                     }
                 }
 
@@ -2639,12 +2649,13 @@
         // reader
         synchronized (mPackages) {
             final Iterator<PackageParser.Package> i = mPackages.values().iterator();
+            final int userId = UserId.getUserId(Binder.getCallingUid());
             while (i.hasNext()) {
                 final PackageParser.Package p = i.next();
                 if (p.applicationInfo != null
                         && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
                         && (!mSafeMode || isSystemApp(p))) {
-                    finalList.add(PackageParser.generateApplicationInfo(p, flags));
+                    finalList.add(PackageParser.generateApplicationInfo(p, flags, userId));
                 }
             }
         }
@@ -2660,7 +2671,8 @@
                     && mSettings.isEnabledLPr(provider.info, flags)
                     && (!mSafeMode || (provider.info.applicationInfo.flags
                             &ApplicationInfo.FLAG_SYSTEM) != 0)
-                    ? PackageParser.generateProviderInfo(provider, flags)
+                    ? PackageParser.generateProviderInfo(provider, flags,
+                            UserId.getUserId(Binder.getCallingUid()))
                     : null;
         }
     }
@@ -2674,7 +2686,7 @@
         synchronized (mPackages) {
             final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet()
                     .iterator();
-
+            final int userId = UserId.getUserId(Binder.getCallingUid());
             while (i.hasNext()) {
                 Map.Entry<String, PackageParser.Provider> entry = i.next();
                 PackageParser.Provider p = entry.getValue();
@@ -2683,7 +2695,7 @@
                         && (!mSafeMode || (p.info.applicationInfo.flags
                                 &ApplicationInfo.FLAG_SYSTEM) != 0)) {
                     outNames.add(entry.getKey());
-                    outInfo.add(PackageParser.generateProviderInfo(p, 0));
+                    outInfo.add(PackageParser.generateProviderInfo(p, 0, userId));
                 }
             }
         }
@@ -2696,19 +2708,21 @@
         // reader
         synchronized (mPackages) {
             final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
+            final int userId = UserId.getUserId(Binder.getCallingUid());
             while (i.hasNext()) {
                 final PackageParser.Provider p = i.next();
                 if (p.info.authority != null
                         && (processName == null
                                 || (p.info.processName.equals(processName)
-                                        && p.info.applicationInfo.uid == uid))
+                                        && UserId.getAppId(p.info.applicationInfo.uid)
+                                            == UserId.getAppId(uid)))
                         && mSettings.isEnabledLPr(p.info, flags)
                         && (!mSafeMode
                                 || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
                     if (finalList == null) {
                         finalList = new ArrayList<ProviderInfo>(3);
                     }
-                    finalList.add(PackageParser.generateProviderInfo(p, flags));
+                    finalList.add(PackageParser.generateProviderInfo(p, flags, userId));
                 }
             }
         }
@@ -4461,8 +4475,8 @@
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
-            res.activityInfo = PackageParser.generateActivityInfo(activity,
-                    mFlags);
+            res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags,
+                    Binder.getOrigCallingUser());
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = info;
             }
@@ -4637,8 +4651,8 @@
                 return null;
             }
             final ResolveInfo res = new ResolveInfo();
-            res.serviceInfo = PackageParser.generateServiceInfo(service,
-                    mFlags);
+            res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags,
+                    Binder.getOrigCallingUser());
             if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                 res.filter = filter;
             }
@@ -4742,8 +4756,10 @@
                     intent.setPackage(targetPkg);
                 }
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                // TODO: Fix the userId argument
                 am.broadcastIntent(null, intent, null, finishedReceiver,
-                        0, null, null, null, finishedReceiver != null, false);
+                        0, null, null, null, finishedReceiver != null, false,
+                        Binder.getOrigCallingUser());
             } catch (RemoteException ex) {
             }
         }
@@ -6415,10 +6431,6 @@
             // package that we deleted.
             if(deletedPkg) {
                 File restoreFile = new File(deletedPackage.mPath);
-                if (restoreFile == null) {
-                    Slog.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
-                    return;
-                }
                 // Parse old package
                 boolean oldOnSd = isExternal(deletedPackage);
                 int oldParseFlags  = mDefParseFlags | PackageParser.PARSE_CHATTY |
@@ -7584,7 +7596,7 @@
                         "Unknown component: " + packageName
                         + "/" + className);
             }
-            if (!allowedByPermission && (uid != pkgSetting.userId)) {
+            if (!allowedByPermission && (!UserId.isSameApp(uid, pkgSetting.userId))) {
                 throw new SecurityException(
                         "Permission Denial: attempt to change component state from pid="
                         + Binder.getCallingPid()
@@ -8673,4 +8685,8 @@
             return mSettings.getVerifierDeviceIdentityLPw();
         }
     }
+
+    public List<UserInfo> getUsers() {
+        return mUserManager.getUsers();
+    }
 }
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 3616aa2..ebf954b 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -200,11 +200,7 @@
                 return null;
             }
             s = new SharedUserSetting(name, pkgFlags);
-            if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
-                s.userId = newUserIdLPw(s);
-            } else {
-                s.userId = PackageManagerService.FIRST_APPLICATION_UID;
-            }
+            s.userId = newUserIdLPw(s);
             Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
             // < 0 means we couldn't assign a userid; fall out and return
             // s, which is currently null
@@ -407,7 +403,7 @@
                 }
                 if (sharedUser != null) {
                     p.userId = sharedUser.userId;
-                } else if (PackageManagerService.MULTIPLE_APPLICATION_UIDS) {
+                } else {
                     // Clone the setting here for disabled system packages
                     PackageSetting dis = mDisabledSysPackages.get(name);
                     if (dis != null) {
@@ -430,8 +426,6 @@
                         // Assign new user id
                         p.userId = newUserIdLPw(p);
                     }
-                } else {
-                    p.userId = PackageManagerService.FIRST_APPLICATION_UID;
                 }
             }
             if (p.userId < 0) {
@@ -598,13 +592,13 @@
     }
 
     private boolean addUserIdLPw(int uid, Object obj, Object name) {
-        if (uid >= PackageManagerService.FIRST_APPLICATION_UID + PackageManagerService.MAX_APPLICATION_UIDS) {
+        if (uid > Process.LAST_APPLICATION_UID) {
             return false;
         }
 
-        if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+        if (uid >= Process.FIRST_APPLICATION_UID) {
             int N = mUserIds.size();
-            final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+            final int index = uid - Process.FIRST_APPLICATION_UID;
             while (index >= N) {
                 mUserIds.add(null);
                 N++;
@@ -629,9 +623,9 @@
     }
 
     public Object getUserIdLPr(int uid) {
-        if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+        if (uid >= Process.FIRST_APPLICATION_UID) {
             final int N = mUserIds.size();
-            final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+            final int index = uid - Process.FIRST_APPLICATION_UID;
             return index < N ? mUserIds.get(index) : null;
         } else {
             return mOtherUserIds.get(uid);
@@ -639,9 +633,9 @@
     }
 
     private void removeUserIdLPw(int uid) {
-        if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+        if (uid >= Process.FIRST_APPLICATION_UID) {
             final int N = mUserIds.size();
-            final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+            final int index = uid - Process.FIRST_APPLICATION_UID;
             if (index < N) mUserIds.set(index, null);
         } else {
             mOtherUserIds.remove(uid);
@@ -649,9 +643,9 @@
     }
 
     private void replaceUserIdLPw(int uid, Object obj) {
-        if (uid >= PackageManagerService.FIRST_APPLICATION_UID) {
+        if (uid >= Process.FIRST_APPLICATION_UID) {
             final int N = mUserIds.size();
-            final int index = uid - PackageManagerService.FIRST_APPLICATION_UID;
+            final int index = uid - Process.FIRST_APPLICATION_UID;
             if (index < N) mUserIds.set(index, obj);
         } else {
             mOtherUserIds.put(uid, obj);
@@ -1898,17 +1892,17 @@
         for (int i = 0; i < N; i++) {
             if (mUserIds.get(i) == null) {
                 mUserIds.set(i, obj);
-                return PackageManagerService.FIRST_APPLICATION_UID + i;
+                return Process.FIRST_APPLICATION_UID + i;
             }
         }
 
         // None left?
-        if (N >= PackageManagerService.MAX_APPLICATION_UIDS) {
+        if (N > (Process.LAST_APPLICATION_UID-Process.FIRST_APPLICATION_UID)) {
             return -1;
         }
 
         mUserIds.add(obj);
-        return PackageManagerService.FIRST_APPLICATION_UID + N;
+        return Process.FIRST_APPLICATION_UID + N;
     }
 
     public VerifierDeviceIdentity getVerifierDeviceIdentityLPw() {
@@ -2018,6 +2012,39 @@
         return false;
     }
 
+    static final void printFlags(PrintWriter pw, int val, Object[] spec) {
+        pw.print("[ ");
+        for (int i=0; i<spec.length; i+=2) {
+            int mask = (Integer)spec[i];
+            if ((val & mask) != 0) {
+                pw.print(spec[i+1]);
+                pw.print(" ");
+            }
+        }
+        pw.print("]");
+    }
+
+    static final Object[] FLAG_DUMP_SPEC = new Object[] {
+        ApplicationInfo.FLAG_SYSTEM, "SYSTEM",
+        ApplicationInfo.FLAG_DEBUGGABLE, "DEBUGGABLE",
+        ApplicationInfo.FLAG_HAS_CODE, "HAS_CODE",
+        ApplicationInfo.FLAG_PERSISTENT, "PERSISTENT",
+        ApplicationInfo.FLAG_FACTORY_TEST, "FACTORY_TEST",
+        ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING, "ALLOW_TASK_REPARENTING",
+        ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA, "ALLOW_CLEAR_USER_DATA",
+        ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, "UPDATED_SYSTEM_APP",
+        ApplicationInfo.FLAG_TEST_ONLY, "TEST_ONLY",
+        ApplicationInfo.FLAG_VM_SAFE_MODE, "VM_SAFE_MODE",
+        ApplicationInfo.FLAG_ALLOW_BACKUP, "ALLOW_BACKUP",
+        ApplicationInfo.FLAG_KILL_AFTER_RESTORE, "KILL_AFTER_RESTORE",
+        ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
+        ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
+        ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
+        ApplicationInfo.FLAG_STOPPED, "STOPPED",
+        ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+        ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+    };
+
     void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) {
         final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         final Date date = new Date();
@@ -2058,6 +2085,7 @@
             pw.print("    nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
             pw.print("    versionCode="); pw.println(ps.versionCode);
             if (ps.pkg != null) {
+                pw.print("    flags="); printFlags(pw, ps.pkg.applicationInfo.flags, FLAG_DUMP_SPEC); pw.println();
                 pw.print("    versionName="); pw.println(ps.pkg.mVersionName);
                 pw.print("    dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
                 pw.print("    targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManager.java
index 2687728..5eacf4a 100644
--- a/services/java/com/android/server/pm/UserManager.java
+++ b/services/java/com/android/server/pm/UserManager.java
@@ -24,6 +24,7 @@
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.SystemClock;
+import android.os.UserId;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -169,9 +170,10 @@
      * </user>
      */
     private void writeUser(UserInfo userInfo) {
+        FileOutputStream fos = null;
         try {
             final File mUserFile = new File(mUsersDir, userInfo.id + ".xml");
-            final FileOutputStream fos = new FileOutputStream(mUserFile);
+            fos = new FileOutputStream(mUserFile);
             final BufferedOutputStream bos = new BufferedOutputStream(fos);
 
             // XmlSerializer serializer = XmlUtils.serializerInstance();
@@ -193,6 +195,13 @@
             serializer.endDocument();
         } catch (IOException ioe) {
             Slog.e(LOG_TAG, "Error writing user info " + userInfo.id + "\n" + ioe);
+        } finally {
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException ioe) {
+                }
+            }
         }
     }
 
@@ -205,8 +214,9 @@
      * </users>
      */
     private void writeUserList() {
+        FileOutputStream fos = null;
         try {
-            final FileOutputStream fos = new FileOutputStream(mUserListFile);
+            fos = new FileOutputStream(mUserListFile);
             final BufferedOutputStream bos = new BufferedOutputStream(fos);
 
             // XmlSerializer serializer = XmlUtils.serializerInstance();
@@ -229,6 +239,13 @@
             serializer.endDocument();
         } catch (IOException ioe) {
             Slog.e(LOG_TAG, "Error writing user list");
+        } finally {
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException ioe) {
+                }
+            }
         }
     }
 
@@ -330,7 +347,7 @@
             // Don't do it for the primary user, it will become recursive.
             if (userId == 0)
                 continue;
-            mInstaller.createUserData(packageName, PackageManager.getUid(userId, uid),
+            mInstaller.createUserData(packageName, UserId.getUid(userId, uid),
                     userId);
         }
     }
@@ -367,6 +384,8 @@
 
     /**
      * Returns the next available user id, filling in any holes in the ids.
+     * TODO: May not be a good idea to recycle ids, in case it results in confusion
+     * for data and battery stats collection, or unexpected cross-talk.
      * @return
      */
     private int getNextAvailableId() {
@@ -390,14 +409,8 @@
         FileUtils.setPermissions(userPath.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
                 | FileUtils.S_IXOTH, -1, -1);
 
-        // Create the individual data directories
-        for (ApplicationInfo app : apps) {
-            if (app.uid > android.os.Process.FIRST_APPLICATION_UID
-                    && app.uid < PackageManager.PER_USER_RANGE) {
-                mInstaller.createUserData(app.packageName,
-                        PackageManager.getUid(id, app.uid), id);
-            }
-        }
+        mInstaller.cloneUserData(0, id, false);
+
         final long stopTime = SystemClock.elapsedRealtime();
         Log.i(LOG_TAG,
                 "Time to create " + apps.size() + " packages = " + (stopTime - startTime) + "ms");
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 8f51466..ed83fbe 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -46,6 +46,7 @@
 import android.os.SystemProperties;
 import android.os.UEventObserver;
 import android.provider.Settings;
+import android.util.Pair;
 import android.util.Slog;
 
 import java.io.File;
@@ -54,7 +55,10 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * UsbDeviceManager manages USB state in device mode.
@@ -88,6 +92,8 @@
     // which need debouncing.
     private static final int UPDATE_DELAY = 1000;
 
+    private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
+
     private UsbHandler mHandler;
     private boolean mBootCompleted;
 
@@ -98,6 +104,7 @@
     private final boolean mHasUsbAccessory;
     private boolean mUseUsbNotification;
     private boolean mAdbEnabled;
+    private Map<String, List<Pair<String, String>>> mOemModeMap;
 
     private class AdbSettingsObserver extends ContentObserver {
         public AdbSettingsObserver() {
@@ -138,6 +145,8 @@
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
         initRndisAddress();
 
+        readOemUsbOverrideConfig();
+
         // create a thread for our Handler
         HandlerThread thread = new HandlerThread("UsbDeviceManager",
                 Process.THREAD_PRIORITY_BACKGROUND);
@@ -259,6 +268,10 @@
                 // persist.sys.usb.config should never be unset.  But if it is, set it to "adb"
                 // so we have a chance of debugging what happened.
                 mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
+
+                // Check if USB mode needs to be overridden depending on OEM specific bootmode.
+                mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);
+
                 // sanity check the sys.usb.config system property
                 // this may be necessary if we crashed while switching USB configurations
                 String config = SystemProperties.get("sys.usb.config", "none");
@@ -381,7 +394,11 @@
         }
 
         private void setEnabledFunctions(String functions, boolean makeDefault) {
-            if (functions != null && makeDefault) {
+
+            // Do not update persystent.sys.usb.config if the device is booted up
+            // with OEM specific mode.
+            if (functions != null && makeDefault && !needsOemUsbOverride()) {
+
                 if (mAdbEnabled) {
                     functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
                 } else {
@@ -410,6 +427,10 @@
                 if (functions == null) {
                     functions = mDefaultFunctions;
                 }
+
+                // Override with bootmode specific usb mode if needed
+                functions = processOemUsbOverride(functions);
+
                 if (mAdbEnabled) {
                     functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
                 } else {
@@ -671,6 +692,53 @@
         }
     }
 
+    private void readOemUsbOverrideConfig() {
+        String[] configList = mContext.getResources().getStringArray(
+            com.android.internal.R.array.config_oemUsbModeOverride);
+
+        if (configList != null) {
+            for (String config: configList) {
+                String[] items = config.split(":");
+                if (items.length == 3) {
+                    if (mOemModeMap == null) {
+                        mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
+                    }
+                    List overrideList = mOemModeMap.get(items[0]);
+                    if (overrideList == null) {
+                        overrideList = new LinkedList<Pair<String, String>>();
+                        mOemModeMap.put(items[0], overrideList);
+                    }
+                    overrideList.add(new Pair<String, String>(items[1], items[2]));
+                }
+            }
+        }
+    }
+
+    private boolean needsOemUsbOverride() {
+        if (mOemModeMap == null) return false;
+
+        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+        return (mOemModeMap.get(bootMode) != null) ? true : false;
+    }
+
+    private String processOemUsbOverride(String usbFunctions) {
+        if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
+
+        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+
+        List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
+        if (overrides != null) {
+            for (Pair<String, String> pair: overrides) {
+                if (pair.first.equals(usbFunctions)) {
+                    Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
+                    return pair.second;
+                }
+            }
+        }
+        // return passed in functions as is.
+        return usbFunctions;
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw) {
         if (mHandler != null) {
             mHandler.dump(fd, pw);
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index a4f0a0c2..56c3519 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -668,25 +668,6 @@
         }
 
         @SuppressWarnings("unused")
-        public int getMaxEventsPerSecond() {
-            int result = 0;
-            try {
-                result = Integer.parseInt(SystemProperties.get("windowsmgr.max_events_per_sec"));
-            } catch (NumberFormatException e) {
-            }
-            if (result < 1) {
-                // This number equates to the refresh rate * 1.5. The rate should be at least
-                // equal to the screen refresh rate. We increase the rate by 50% to compensate for
-                // the discontinuity between the actual rate that events come in at (they do
-                // not necessarily come in constantly and are not handled synchronously).
-                // Ideally, we would use Display.getRefreshRate(), but as this does not necessarily
-                // return a sensible result, we use '60' as our default assumed refresh rate.
-                result = 90;
-            }
-            return result;
-        }
-
-        @SuppressWarnings("unused")
         public int getPointerLayer() {
             return mWindowManagerService.mPolicy.windowTypeToLayerLw(
                     WindowManager.LayoutParams.TYPE_POINTER)
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 55fb038..04a039f 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import java.io.PrintWriter;
+
 import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
@@ -96,6 +98,46 @@
     final Matrix mTmpMatrix = new Matrix();
     final float[] mTmpFloats = new float[9];
 
+    public void printTo(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mSurface="); pw.print(mSurface);
+                pw.print(" mWidth="); pw.print(mWidth);
+                pw.print(" mHeight="); pw.println(mHeight);
+        pw.print(prefix); pw.print("mBlackFrame="); pw.println(mBlackFrame);
+        pw.print(prefix); pw.print("mSnapshotRotation="); pw.print(mSnapshotRotation);
+                pw.print(" mSnapshotDeltaRotation="); pw.print(mSnapshotDeltaRotation);
+                pw.print(" mCurRotation="); pw.println(mCurRotation);
+        pw.print(prefix); pw.print("mOriginalRotation="); pw.print(mOriginalRotation);
+                pw.print(" mOriginalWidth="); pw.print(mOriginalWidth);
+                pw.print(" mOriginalHeight="); pw.println(mOriginalHeight);
+        pw.print(prefix); pw.print("mStarted="); pw.print(mStarted);
+                pw.print(" mAnimRunning="); pw.print(mAnimRunning);
+                pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady);
+                pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime);
+        pw.print(prefix); pw.print("mStartExitAnimation="); pw.print(mStartExitAnimation);
+                pw.print(" "); mStartExitTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mStartEnterAnimation="); pw.print(mStartEnterAnimation);
+                pw.print(" "); mStartEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mFinishExitAnimation="); pw.print(mFinishExitAnimation);
+                pw.print(" "); mFinishExitTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mFinishEnterAnimation="); pw.print(mFinishEnterAnimation);
+                pw.print(" "); mFinishEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation);
+                pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
+                pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mLastRotateExitAnimation=");
+                pw.print(mLastRotateExitAnimation);
+                pw.print(" "); mLastRotateExitTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mExitTransformation=");
+                mExitTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mEnterTransformation=");
+                mEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
+                mSnapshotInitialMatrix.printShortString(pw);
+                pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
+                pw.println();
+    }
+
     public ScreenRotationAnimation(Context context, SurfaceSession session,
             boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
         mContext = context;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 24b6064..bdbaab4 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -95,6 +95,7 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 import android.util.TypedValue;
+import android.view.Choreographer;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.IApplicationToken;
@@ -141,7 +142,8 @@
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
-        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
+        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
+        Choreographer.OnAnimateListener {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
@@ -248,6 +250,7 @@
 
     private static final String SYSTEM_SECURE = "ro.secure";
     private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
+    private static final String SYSTEM_HEADLESS = "ro.config.headless";
 
     /**
      * Condition waited on by {@link #reenableKeyguard} to know the call to
@@ -257,6 +260,8 @@
      */
     private boolean mKeyguardDisabled = false;
 
+    private final boolean mHeadless;
+
     private static final int ALLOW_DISABLE_YES = 1;
     private static final int ALLOW_DISABLE_NO = 0;
     private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager
@@ -456,7 +461,7 @@
     int mDeferredRotationPauseCount;
 
     boolean mLayoutNeeded = true;
-    boolean mAnimationPending = false;
+    boolean mTraversalScheduled = false;
     boolean mDisplayFrozen = false;
     boolean mWaitingForConfig = false;
     boolean mWindowsFreezingScreen = false;
@@ -503,14 +508,18 @@
     final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
     final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
 
-    H mH = new H();
+    final H mH = new H();
+
+    final Choreographer mChoreographer = Choreographer.getInstance();
 
     WindowState mCurrentFocus = null;
     WindowState mLastFocus = null;
 
-    // This just indicates the window the input method is on top of, not
-    // necessarily the window its input is going to.
+    /** This just indicates the window the input method is on top of, not
+     * necessarily the window its input is going to. */
     WindowState mInputMethodTarget = null;
+
+    /** If true hold off on modifying the animation layer of mInputMethodTarget */
     boolean mInputMethodTargetWaitingAnim;
     int mInputMethodAnimLayerAdjustment;
 
@@ -559,6 +568,7 @@
 
     float mWindowAnimationScale = 1.0f;
     float mTransitionAnimationScale = 1.0f;
+    float mAnimatorDurationScale = 1.0f;
 
     final InputManager mInputManager;
 
@@ -570,6 +580,29 @@
 
     DragState mDragState = null;
 
+    /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple
+     * methods. */
+    private class LayoutAndSurfaceFields {
+        private boolean mAnimating = false;
+        private boolean mWallpaperForceHidingChanged = false;
+        private boolean mTokenMayBeDrawn = false;
+        private boolean mWallpaperMayChange = false;
+        private boolean mForceHiding = false;
+        private WindowState mDetachedWallpaper = null;
+        private WindowState mWindowAnimationBackground = null;
+        private int mWindowAnimationBackgroundColor = 0;
+        private boolean mOrientationChangeComplete = true;
+        private int mAdjResult = 0;
+        private Session mHoldScreen = null;
+        private boolean mObscured = false;
+        private boolean mBlurring = false;
+        private boolean mDimming = false;
+        private boolean mSyswin = false;
+        private float mScreenBrightness = -1;
+        private float mButtonBrightness = -1;
+    }
+    private LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields();
+
     final class DragInputEventReceiver extends InputEventReceiver {
         public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
@@ -691,6 +724,7 @@
             Looper.prepare();
             WindowManagerService s = new WindowManagerService(mContext, mPM,
                     mHaveInputMethods, mAllowBootMessages);
+            s.mChoreographer.addOnAnimateListener(s);
             android.os.Process.setThreadPriority(
                     android.os.Process.THREAD_PRIORITY_DISPLAY);
             android.os.Process.setCanSelfBackground(false);
@@ -758,6 +792,7 @@
         mAllowBootMessages = showBootMsgs;
         mLimitedAlphaCompositing = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_sf_limitedAlpha);
+        mHeadless = "1".equals(SystemProperties.get(SYSTEM_HEADLESS, "0"));
 
         mPowerManager = pm;
         mPowerManager.setPolicy(mPolicy);
@@ -774,6 +809,8 @@
                 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
         mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
                 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+        mAnimatorDurationScale = Settings.System.getFloat(context.getContentResolver(),
+                Settings.System.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale);
 
         // Track changes to DevicePolicyManager state so we can enable/disable keyguard.
         IntentFilter filter = new IntentFilter();
@@ -1082,6 +1119,11 @@
         return false;
     }
 
+    /**
+     * Dig through the WindowStates and find the one that the Input Method will target.
+     * @param willMove
+     * @return The index+1 in mWindows of the discovered target.
+     */
     int findDesiredInputMethodWindowIndexLocked(boolean willMove) {
         final ArrayList<WindowState> localmWindows = mWindows;
         final int N = localmWindows.size();
@@ -1114,8 +1156,10 @@
             }
         }
 
+        // Now w is either mWindows[0] or an IME (or null if mWindows is empty).
+
         if (DEBUG_INPUT_METHOD && willMove) Slog.v(TAG, "Proposed new IME target: " + w);
-        
+
         // Now, a special case -- if the last target's window is in the
         // process of exiting, and is above the new target, keep on the
         // last target to avoid flicker.  Consider for example a Dialog with
@@ -1147,8 +1191,7 @@
                 WindowState highestTarget = null;
                 int highestPos = 0;
                 if (token.animating || token.animation != null) {
-                    int pos = 0;
-                    pos = localmWindows.indexOf(curTarget);
+                    int pos = localmWindows.indexOf(curTarget);
                     while (pos >= 0) {
                         WindowState win = localmWindows.get(pos);
                         if (win.mAppToken != token) {
@@ -2543,8 +2586,12 @@
             if (win == null) {
                 return 0;
             }
-            win.mRequestedWidth = requestedWidth;
-            win.mRequestedHeight = requestedHeight;
+            if (win.mRequestedWidth != requestedWidth
+                    || win.mRequestedHeight != requestedHeight) {
+                win.mLayoutNeeded = true;
+                win.mRequestedWidth = requestedWidth;
+                win.mRequestedHeight = requestedHeight;
+            }
             if (attrs != null && seq == win.mSeq) {
                 win.mSystemUiVisibility = systemUiVisibility;
             }
@@ -2565,6 +2612,9 @@
                 }
                 flagChanges = win.mAttrs.flags ^= attrs.flags;
                 attrChanges = win.mAttrs.copyFrom(attrs);
+                if ((attrChanges&WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
+                    win.mLayoutNeeded = true;
+                }
             }
 
             if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": " + win.mAttrs);
@@ -4650,6 +4700,7 @@
         switch (which) {
             case 0: mWindowAnimationScale = fixScale(scale); break;
             case 1: mTransitionAnimationScale = fixScale(scale); break;
+            case 2: mAnimatorDurationScale = fixScale(scale); break;
         }
 
         // Persist setting
@@ -4669,6 +4720,9 @@
             if (scales.length >= 2) {
                 mTransitionAnimationScale = fixScale(scales[1]);
             }
+            if (scales.length >= 3) {
+                mAnimatorDurationScale = fixScale(scales[2]);
+            }
         }
 
         // Persist setting
@@ -4679,12 +4733,14 @@
         switch (which) {
             case 0: return mWindowAnimationScale;
             case 1: return mTransitionAnimationScale;
+            case 2: return mAnimatorDurationScale;
         }
         return 0;
     }
 
     public float[] getAnimationScales() {
-        return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
+        return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
+                mAnimatorDurationScale };
     }
 
     public int getSwitchState(int sw) {
@@ -4837,7 +4893,7 @@
 
     public void performBootTimeout() {
         synchronized(mWindowMap) {
-            if (mDisplayEnabled) {
+            if (mDisplayEnabled || mHeadless) {
                 return;
             }
             Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
@@ -5005,6 +5061,8 @@
     // TODO: more accounting of which pid(s) turned it on, keep count,
     // only allow disables from pids which have count on, etc.
     public void showStrictModeViolation(boolean on) {
+        if (mHeadless) return;
+
         int pid = Binder.getCallingPid();
         synchronized(mWindowMap) {
             // Ignoring requests to enable the red border from clients
@@ -5383,7 +5441,7 @@
                 if (mScreenRotationAnimation.setRotation(rotation, mFxSession,
                         MAX_ANIMATION_DURATION, mTransitionAnimationScale,
                         mCurDisplayWidth, mCurDisplayHeight)) {
-                    requestAnimationLocked(0);
+                    mChoreographer.scheduleAnimation();
                 }
             }
             Surface.setOrientation(0, rotation);
@@ -6197,7 +6255,6 @@
                         final IBinder winBinder = window.asBinder();
                         token = new Binder();
                         mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
-                        mDragState.mSurface = surface;
                         token = mDragState.mToken = new Binder();
 
                         // 5 second timeout for this window to actually begin the drag
@@ -6506,7 +6563,7 @@
     final class H extends Handler {
         public static final int REPORT_FOCUS_CHANGE = 2;
         public static final int REPORT_LOSING_FOCUS = 3;
-        public static final int ANIMATE = 4;
+        public static final int DO_TRAVERSAL = 4;
         public static final int ADD_STARTING = 5;
         public static final int REMOVE_STARTING = 6;
         public static final int FINISHED_STARTING = 7;
@@ -6600,9 +6657,9 @@
                     }
                 } break;
 
-                case ANIMATE: {
+                case DO_TRAVERSAL: {
                     synchronized(mWindowMap) {
-                        mAnimationPending = false;
+                        mTraversalScheduled = false;
                         performLayoutAndPlaceSurfacesLocked();
                     }
                 } break;
@@ -6818,12 +6875,14 @@
                             Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
                     Settings.System.putFloat(mContext.getContentResolver(),
                             Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+                    Settings.System.putFloat(mContext.getContentResolver(),
+                            Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
                     break;
                 }
 
                 case FORCE_GC: {
                     synchronized(mWindowMap) {
-                        if (mAnimationPending) {
+                        if (mChoreographer.isAnimationScheduled()) {
                             // If we are animating, don't do the gc now but
                             // delay a bit so we don't interrupt the animation.
                             mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
@@ -7362,7 +7421,7 @@
         try {
             performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
 
-            int N = mPendingRemove.size();
+            final int N = mPendingRemove.size();
             if (N > 0) {
                 if (mPendingRemoveTmp.length < N) {
                     mPendingRemoveTmp = new WindowState[N+10];
@@ -7382,7 +7441,7 @@
             } else {
                 mInLayout = false;
                 if (mLayoutNeeded) {
-                    requestAnimationLocked(0);
+                    requestTraversalLocked();
                 }
             }
             if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
@@ -7395,9 +7454,9 @@
         }
     }
 
-    private final int performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
+    private final void performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
         if (!mLayoutNeeded) {
-            return 0;
+            return;
         }
         
         mLayoutNeeded = false;
@@ -7429,7 +7488,7 @@
         // to another window).
         int topAttached = -1;
         for (i = N-1; i >= 0; i--) {
-            WindowState win = mWindows.get(i);
+            final WindowState win = mWindows.get(i);
 
             // Don't do layout of a window if it is not visible, or
             // soon won't be visible, to avoid wasting time and funky
@@ -7460,12 +7519,13 @@
             // if they want.  (We do the normal layout for INVISIBLE
             // windows, since that means "perform layout as normal,
             // just don't display").
-            if (!gone || !win.mHaveFrame) {
+            if (!gone || !win.mHaveFrame || win.mLayoutNeeded) {
                 if (!win.mLayoutAttached) {
                     if (initial) {
                         //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                         win.mContentChanged = false;
                     }
+                    win.mLayoutNeeded = false;
                     win.prelayout();
                     mPolicy.layoutWindowLw(win, win.mAttrs, null);
                     win.mLayoutSeq = seq;
@@ -7484,7 +7544,7 @@
         // XXX does not deal with windows that are attached to windows
         // that are themselves attached.
         for (i = topAttached; i >= 0; i--) {
-            WindowState win = mWindows.get(i);
+            final WindowState win = mWindows.get(i);
 
             if (win.mLayoutAttached) {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
@@ -7497,11 +7557,12 @@
                 // windows, since that means "perform layout as normal,
                 // just don't display").
                 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
-                        || !win.mHaveFrame) {
+                        || !win.mHaveFrame || win.mLayoutNeeded) {
                     if (initial) {
                         //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
                         win.mContentChanged = false;
                     }
+                    win.mLayoutNeeded = false;
                     win.prelayout();
                     mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
                     win.mLayoutSeq = seq;
@@ -7519,7 +7580,7 @@
             mInputMonitor.updateInputWindowsLw(false /*force*/);
         }
 
-        return mPolicy.finishLayoutLw();
+        mPolicy.finishLayoutLw();
     }
 
     void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
@@ -7541,6 +7602,1008 @@
         }
     }
 
+    /**
+     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
+     * Update animations of all applications, including those associated with exiting/removed apps.
+     *
+     * @param currentTime The time which animations use for calculating transitions.
+     * @param innerDw Width of app window.
+     * @param innerDh Height of app window.
+     * @return true if rotation has stopped, false otherwise
+     */
+    private boolean updateAppsAndRotationAnimationsLocked(long currentTime,
+                                                          int innerDw, int innerDh) {
+        int i;
+        final int NAT = mAppTokens.size();
+        for (i=0; i<NAT; i++) {
+            if (mAppTokens.get(i).stepAnimationLocked(currentTime,
+                    innerDw, innerDh)) {
+                mInnerFields.mAnimating = true;
+            }
+        }
+        final int NEAT = mExitingAppTokens.size();
+        for (i=0; i<NEAT; i++) {
+            if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime,
+                    innerDw, innerDh)) {
+                mInnerFields.mAnimating = true;
+            }
+        }
+
+        boolean updateRotation = false;
+        if (mScreenRotationAnimation != null) {
+            if (mScreenRotationAnimation.isAnimating()) {
+                if (mScreenRotationAnimation.stepAnimation(currentTime)) {
+                    mInnerFields.mAnimating = true;
+                } else {
+                    updateRotation = true;
+                    mScreenRotationAnimation.kill();
+                    mScreenRotationAnimation = null;
+                }
+            }
+        }
+
+        return updateRotation;
+    }
+
+    /**
+     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
+     *
+     * @param currentTime The time which animations use for calculating transitions.
+     * @param innerDw Width of app window.
+     * @param innerDh Height of app window.
+     */
+    private void updateWindowsAndWallpaperLocked(final long currentTime,
+                                                 final int innerDw, final int innerDh) {
+        int i;
+        final int N = mWindows.size();
+
+        for (i=N-1; i>=0; i--) {
+            WindowState w = mWindows.get(i);
+
+            final WindowManager.LayoutParams attrs = w.mAttrs;
+
+            if (w.mSurface != null) {
+                // Take care of the window being ready to display.
+                if (w.commitFinishDrawingLocked(currentTime)) {
+                    if ((w.mAttrs.flags
+                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                        if (DEBUG_WALLPAPER) Slog.v(TAG,
+                                "First draw done in potential wallpaper target " + w);
+                        mInnerFields.mWallpaperMayChange = true;
+                    }
+                }
+
+                final boolean wasAnimating = w.mAnimating;
+
+                int animDw = innerDw;
+                int animDh = innerDh;
+
+                // If the window has moved due to its containing
+                // content frame changing, then we'd like to animate
+                // it.  The checks here are ordered by what is least
+                // likely to be true first.
+                if (w.shouldAnimateMove()) {
+                    // Frame has moved, containing content frame
+                    // has also moved, and we're not currently animating...
+                    // let's do something.
+                    Animation a = AnimationUtils.loadAnimation(mContext,
+                            com.android.internal.R.anim.window_move_from_decor);
+                    w.setAnimation(a);
+                    animDw = w.mLastFrame.left - w.mFrame.left;
+                    animDh = w.mLastFrame.top - w.mFrame.top;
+                }
+
+                // Execute animation.
+                final boolean nowAnimating = w.stepAnimationLocked(currentTime,
+                        animDw, animDh);
+
+                // If this window is animating, make a note that we have
+                // an animating window and take care of a request to run
+                // a detached wallpaper animation.
+                if (nowAnimating) {
+                    if (w.mAnimation != null) {
+                        if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
+                                && w.mAnimation.getDetachWallpaper()) {
+                            mInnerFields.mDetachedWallpaper = w;
+                        }
+                        if (w.mAnimation.getBackgroundColor() != 0) {
+                            if (mInnerFields.mWindowAnimationBackground == null
+                                    || (w.mAnimLayer <
+                                            mInnerFields.mWindowAnimationBackground.mAnimLayer)) {
+                                mInnerFields.mWindowAnimationBackground = w;
+                                mInnerFields.mWindowAnimationBackgroundColor =
+                                        w.mAnimation.getBackgroundColor();
+                            }
+                        }
+                    }
+                    mInnerFields.mAnimating = true;
+                }
+
+                // If this window's app token is running a detached wallpaper
+                // animation, make a note so we can ensure the wallpaper is
+                // displayed behind it.
+                if (w.mAppToken != null && w.mAppToken.animation != null
+                        && w.mAppToken.animating) {
+                    if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
+                            && w.mAppToken.animation.getDetachWallpaper()) {
+                        mInnerFields.mDetachedWallpaper = w;
+                    }
+                    if (w.mAppToken.animation.getBackgroundColor() != 0) {
+                        if (mInnerFields.mWindowAnimationBackground == null
+                                || (w.mAnimLayer <
+                                        mInnerFields.mWindowAnimationBackground.mAnimLayer)) {
+                            mInnerFields.mWindowAnimationBackground = w;
+                            mInnerFields.mWindowAnimationBackgroundColor =
+                                    w.mAppToken.animation.getBackgroundColor();
+                        }
+                    }
+                }
+
+                if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
+                    mInnerFields.mWallpaperMayChange = true;
+                }
+
+                if (mPolicy.doesForceHide(w, attrs)) {
+                    if (!wasAnimating && nowAnimating) {
+                        if (DEBUG_VISIBILITY) Slog.v(TAG,
+                                "Animation started that could impact force hide: "
+                                + w);
+                        mInnerFields.mWallpaperForceHidingChanged = true;
+                        mFocusMayChange = true;
+                    } else if (w.isReadyForDisplay() && w.mAnimation == null) {
+                        mInnerFields.mForceHiding = true;
+                    }
+                } else if (mPolicy.canBeForceHidden(w, attrs)) {
+                    boolean changed;
+                    if (mInnerFields.mForceHiding) {
+                        changed = w.hideLw(false, false);
+                        if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
+                                "Now policy hidden: " + w);
+                    } else {
+                        changed = w.showLw(false, false);
+                        if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
+                                "Now policy shown: " + w);
+                        if (changed) {
+                            if (mInnerFields.mWallpaperForceHidingChanged
+                                    && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
+                                // Assume we will need to animate.  If
+                                // we don't (because the wallpaper will
+                                // stay with the lock screen), then we will
+                                // clean up later.
+                                Animation a = mPolicy.createForceHideEnterAnimation();
+                                if (a != null) {
+                                    w.setAnimation(a);
+                                }
+                            }
+                            if (mCurrentFocus == null ||
+                                    mCurrentFocus.mLayer < w.mLayer) {
+                                // We are showing on to of the current
+                                // focus, so re-evaluate focus to make
+                                // sure it is correct.
+                                mFocusMayChange = true;
+                            }
+                        }
+                    }
+                    if (changed && (attrs.flags
+                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                        mInnerFields.mWallpaperMayChange = true;
+                    }
+                }
+
+                mPolicy.animatingWindowLw(w, attrs);
+            }
+
+            final AppWindowToken atoken = w.mAppToken;
+            if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
+                if (atoken.lastTransactionSequence != mTransactionSequence) {
+                    atoken.lastTransactionSequence = mTransactionSequence;
+                    atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
+                    atoken.startingDisplayed = false;
+                }
+                if ((w.isOnScreen() || w.mAttrs.type
+                        == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
+                        && !w.mExiting && !w.mDestroying) {
+                    if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
+                        Slog.v(TAG, "Eval win " + w + ": isDrawn="
+                                + w.isDrawnLw()
+                                + ", isAnimating=" + w.isAnimating());
+                        if (!w.isDrawnLw()) {
+                            Slog.v(TAG, "Not displayed: s=" + w.mSurface
+                                    + " pv=" + w.mPolicyVisibility
+                                    + " dp=" + w.mDrawPending
+                                    + " cdp=" + w.mCommitDrawPending
+                                    + " ah=" + w.mAttachedHidden
+                                    + " th=" + atoken.hiddenRequested
+                                    + " a=" + w.mAnimating);
+                        }
+                    }
+                    if (w != atoken.startingWindow) {
+                        if (!atoken.freezingScreen || !w.mAppFreezing) {
+                            atoken.numInterestingWindows++;
+                            if (w.isDrawnLw()) {
+                                atoken.numDrawnWindows++;
+                                if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
+                                        "tokenMayBeDrawn: " + atoken
+                                        + " freezingScreen=" + atoken.freezingScreen
+                                        + " mAppFreezing=" + w.mAppFreezing);
+                                mInnerFields.mTokenMayBeDrawn = true;
+                            }
+                        }
+                    } else if (w.isDrawnLw()) {
+                        atoken.startingDisplayed = true;
+                    }
+                }
+            } else if (w.mReadyToShow) {
+                w.performShowLocked();
+            }
+        } // end forall windows
+    }
+
+    /**
+     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
+     *
+     * @return bitmap indicating if another pass through layout must be made.
+     */
+    private int testTokenMayBeDrawnLocked() {
+        int changes = 0;
+        // See if any windows have been drawn, so they (and others
+        // associated with them) can now be shown.
+        final int NT = mAppTokens.size();
+        for (int i=0; i<NT; i++) {
+            AppWindowToken wtoken = mAppTokens.get(i);
+            if (wtoken.freezingScreen) {
+                int numInteresting = wtoken.numInterestingWindows;
+                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                    if (DEBUG_VISIBILITY) Slog.v(TAG,
+                            "allDrawn: " + wtoken
+                            + " interesting=" + numInteresting
+                            + " drawn=" + wtoken.numDrawnWindows);
+                    wtoken.showAllWindowsLocked();
+                    unsetAppFreezingScreenLocked(wtoken, false, true);
+                    if (DEBUG_ORIENTATION) Slog.i(TAG,
+                            "Setting mOrientationChangeComplete=true because wtoken "
+                            + wtoken + " numInteresting=" + numInteresting
+                            + " numDrawn=" + wtoken.numDrawnWindows);
+                    mInnerFields.mOrientationChangeComplete = true;
+                }
+            } else if (!wtoken.allDrawn) {
+                int numInteresting = wtoken.numInterestingWindows;
+                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                    if (DEBUG_VISIBILITY) Slog.v(TAG,
+                            "allDrawn: " + wtoken
+                            + " interesting=" + numInteresting
+                            + " drawn=" + wtoken.numDrawnWindows);
+                    wtoken.allDrawn = true;
+                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
+
+                    // We can now show all of the drawn windows!
+                    if (!mOpeningApps.contains(wtoken)) {
+                        wtoken.showAllWindowsLocked();
+                    }
+                }
+            }
+        }
+
+        return changes;
+    }
+
+    /**
+     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
+     *
+     * @return bitmap indicating if another pass through layout must be made.
+     */
+    public int handleAppTransitionReadyLocked() {
+        int changes = 0;
+        int i;
+        int NN = mOpeningApps.size();
+        boolean goodToGo = true;
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                "Checking " + NN + " opening apps (frozen="
+                + mDisplayFrozen + " timeout="
+                + mAppTransitionTimeout + ")...");
+        if (!mDisplayFrozen && !mAppTransitionTimeout) {
+            // If the display isn't frozen, wait to do anything until
+            // all of the apps are ready.  Otherwise just go because
+            // we'll unfreeze the display when everyone is ready.
+            for (i=0; i<NN && goodToGo; i++) {
+                AppWindowToken wtoken = mOpeningApps.get(i);
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "Check opening app" + wtoken + ": allDrawn="
+                        + wtoken.allDrawn + " startingDisplayed="
+                        + wtoken.startingDisplayed);
+                if (!wtoken.allDrawn && !wtoken.startingDisplayed
+                        && !wtoken.startingMoved) {
+                    goodToGo = false;
+                }
+            }
+        }
+        if (goodToGo) {
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
+            int transit = mNextAppTransition;
+            if (mSkipAppTransitionAnimation) {
+                transit = WindowManagerPolicy.TRANSIT_UNSET;
+            }
+            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
+            mAppTransitionReady = false;
+            mAppTransitionRunning = true;
+            mAppTransitionTimeout = false;
+            mStartingIconInTransition = false;
+            mSkipAppTransitionAnimation = false;
+
+            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
+
+            // If there are applications waiting to come to the
+            // top of the stack, now is the time to move their windows.
+            // (Note that we don't do apps going to the bottom
+            // here -- we want to keep their windows in the old
+            // Z-order until the animation completes.)
+            if (mToTopApps.size() > 0) {
+                NN = mAppTokens.size();
+                for (i=0; i<NN; i++) {
+                    AppWindowToken wtoken = mAppTokens.get(i);
+                    if (wtoken.sendingToTop) {
+                        wtoken.sendingToTop = false;
+                        moveAppWindowsLocked(wtoken, NN, false);
+                    }
+                }
+                mToTopApps.clear();
+            }
+
+            WindowState oldWallpaper = mWallpaperTarget;
+
+            adjustWallpaperWindowsLocked();
+            mInnerFields.mWallpaperMayChange = false;
+
+            // The top-most window will supply the layout params,
+            // and we will determine it below.
+            LayoutParams animLp = null;
+            int bestAnimLayer = -1;
+            boolean fullscreenAnim = false;
+
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "New wallpaper target=" + mWallpaperTarget
+                    + ", lower target=" + mLowerWallpaperTarget
+                    + ", upper target=" + mUpperWallpaperTarget);
+            int foundWallpapers = 0;
+            // Do a first pass through the tokens for two
+            // things:
+            // (1) Determine if both the closing and opening
+            // app token sets are wallpaper targets, in which
+            // case special animations are needed
+            // (since the wallpaper needs to stay static
+            // behind them).
+            // (2) Find the layout params of the top-most
+            // application window in the tokens, which is
+            // what will control the animation theme.
+            final int NC = mClosingApps.size();
+            NN = NC + mOpeningApps.size();
+            for (i=0; i<NN; i++) {
+                AppWindowToken wtoken;
+                int mode;
+                if (i < NC) {
+                    wtoken = mClosingApps.get(i);
+                    mode = 1;
+                } else {
+                    wtoken = mOpeningApps.get(i-NC);
+                    mode = 2;
+                }
+                if (mLowerWallpaperTarget != null) {
+                    if (mLowerWallpaperTarget.mAppToken == wtoken
+                            || mUpperWallpaperTarget.mAppToken == wtoken) {
+                        foundWallpapers |= mode;
+                    }
+                }
+                if (wtoken.appFullscreen) {
+                    WindowState ws = wtoken.findMainWindow();
+                    if (ws != null) {
+                        animLp = ws.mAttrs;
+                        bestAnimLayer = ws.mLayer;
+                        fullscreenAnim = true;
+                    }
+                } else if (!fullscreenAnim) {
+                    WindowState ws = wtoken.findMainWindow();
+                    if (ws != null) {
+                        if (ws.mLayer > bestAnimLayer) {
+                            animLp = ws.mAttrs;
+                            bestAnimLayer = ws.mLayer;
+                        }
+                    }
+                }
+            }
+
+            if (foundWallpapers == 3) {
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "Wallpaper animation!");
+                switch (transit) {
+                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
+                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
+                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
+                        break;
+                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
+                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
+                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
+                        break;
+                }
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "New transit: " + transit);
+            } else if (oldWallpaper != null) {
+                // We are transitioning from an activity with
+                // a wallpaper to one without.
+                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "New transit away from wallpaper: " + transit);
+            } else if (mWallpaperTarget != null) {
+                // We are transitioning from an activity without
+                // a wallpaper to now showing the wallpaper
+                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "New transit into wallpaper: " + transit);
+            }
+
+            // If all closing windows are obscured, then there is
+            // no need to do an animation.  This is the case, for
+            // example, when this transition is being done behind
+            // the lock screen.
+            if (!mPolicy.allowAppAnimationsLw()) {
+                animLp = null;
+            }
+
+            NN = mOpeningApps.size();
+            for (i=0; i<NN; i++) {
+                AppWindowToken wtoken = mOpeningApps.get(i);
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "Now opening app" + wtoken);
+                wtoken.reportedVisible = false;
+                wtoken.inPendingTransaction = false;
+                wtoken.animation = null;
+                setTokenVisibilityLocked(wtoken, animLp, true,
+                        transit, false);
+                wtoken.updateReportedVisibilityLocked();
+                wtoken.waitingToShow = false;
+                wtoken.showAllWindowsLocked();
+            }
+            NN = mClosingApps.size();
+            for (i=0; i<NN; i++) {
+                AppWindowToken wtoken = mClosingApps.get(i);
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "Now closing app" + wtoken);
+                wtoken.inPendingTransaction = false;
+                wtoken.animation = null;
+                setTokenVisibilityLocked(wtoken, animLp, false,
+                        transit, false);
+                wtoken.updateReportedVisibilityLocked();
+                wtoken.waitingToHide = false;
+                // Force the allDrawn flag, because we want to start
+                // this guy's animations regardless of whether it's
+                // gotten drawn.
+                wtoken.allDrawn = true;
+            }
+
+            mNextAppTransitionPackage = null;
+
+            mOpeningApps.clear();
+            mClosingApps.clear();
+
+            // This has changed the visibility of windows, so perform
+            // a new layout to get them all up-to-date.
+            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
+                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+            mLayoutNeeded = true;
+            if (!moveInputMethodWindowsIfNeededLocked(true)) {
+                assignLayersLocked();
+            }
+            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
+                    false /*updateInputWindows*/);
+            mFocusMayChange = false;
+        }
+
+        return changes;
+    }
+
+    /**
+     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
+     *
+     * @return bitmap indicating if another pass through layout must be made.
+     */
+    private int handleAnimatingAndTransitionLocked() {
+        int changes = 0;
+
+        mAppTransitionRunning = false;
+        // Clear information about apps that were moving.
+        mToBottomApps.clear();
+
+        rebuildAppWindowListLocked();
+        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
+        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
+        moveInputMethodWindowsIfNeededLocked(false);
+        mInnerFields.mWallpaperMayChange = true;
+        // Since the window list has been rebuilt, focus might
+        // have to be recomputed since the actual order of windows
+        // might have changed again.
+        mFocusMayChange = true;
+
+        return changes;
+    }
+
+    /**
+     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
+     *
+     * @return bitmap indicating if another pass through layout must be made.
+     */
+    private int animateAwayWallpaperLocked() {
+        int changes = 0;
+        WindowState oldWallpaper = mWallpaperTarget;
+        if (mLowerWallpaperTarget != null
+                && mLowerWallpaperTarget.mAppToken != null) {
+            if (DEBUG_WALLPAPER) Slog.v(TAG,
+                    "wallpaperForceHiding changed with lower="
+                    + mLowerWallpaperTarget);
+            if (DEBUG_WALLPAPER) Slog.v(TAG,
+                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
+                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
+            if (mLowerWallpaperTarget.mAppToken.hidden) {
+                // The lower target has become hidden before we
+                // actually started the animation...  let's completely
+                // re-evaluate everything.
+                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
+                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
+            }
+        }
+        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
+        mInnerFields.mWallpaperMayChange = false;
+        mInnerFields.mWallpaperForceHidingChanged = false;
+        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
+                + " NEW: " + mWallpaperTarget
+                + " LOWER: " + mLowerWallpaperTarget);
+        if (mLowerWallpaperTarget == null) {
+            // Whoops, we don't need a special wallpaper animation.
+            // Clear them out.
+            mInnerFields.mForceHiding = false;
+            for (int i=mWindows.size()-1; i>=0; i--) {
+                WindowState w = mWindows.get(i);
+                if (w.mSurface != null) {
+                    final WindowManager.LayoutParams attrs = w.mAttrs;
+                    if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
+                        if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
+                        mInnerFields.mForceHiding = true;
+                    } else if (mPolicy.canBeForceHidden(w, attrs)) {
+                        if (!w.mAnimating) {
+                            // We set the animation above so it
+                            // is not yet running.
+                            w.clearAnimation();
+                        }
+                    }
+                }
+            }
+        }
+        return changes;
+    }
+
+    /**
+     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
+     *
+     * @return bitmap indicating if another pass through layout must be made.
+     */
+    private int testWallpaperAndBackgroundLocked() {
+        int changes = 0;
+
+        if (mWindowDetachedWallpaper != mInnerFields.mDetachedWallpaper) {
+            if (DEBUG_WALLPAPER) Slog.v(TAG,
+                    "Detached wallpaper changed from " + mWindowDetachedWallpaper
+                    + " to " + mInnerFields.mDetachedWallpaper);
+            mWindowDetachedWallpaper = mInnerFields.mDetachedWallpaper;
+            mInnerFields.mWallpaperMayChange = true;
+        }
+
+        if (mInnerFields.mWindowAnimationBackgroundColor != 0) {
+            // If the window that wants black is the current wallpaper
+            // target, then the black goes *below* the wallpaper so we
+            // don't cause the wallpaper to suddenly disappear.
+            WindowState target = mInnerFields.mWindowAnimationBackground;
+            if (mWallpaperTarget == mInnerFields.mWindowAnimationBackground
+                    || mLowerWallpaperTarget == mInnerFields.mWindowAnimationBackground
+                    || mUpperWallpaperTarget == mInnerFields.mWindowAnimationBackground) {
+                for (int i=0; i<mWindows.size(); i++) {
+                    WindowState w = mWindows.get(i);
+                    if (w.mIsWallpaper) {
+                        target = w;
+                        break;
+                    }
+                }
+            }
+            if (mWindowAnimationBackgroundSurface == null) {
+                mWindowAnimationBackgroundSurface = new DimSurface(mFxSession);
+            }
+            final int dw = mCurDisplayWidth;
+            final int dh = mCurDisplayHeight;
+            mWindowAnimationBackgroundSurface.show(dw, dh,
+                    target.mAnimLayer - LAYER_OFFSET_DIM,
+                    mInnerFields.mWindowAnimationBackgroundColor);
+        } else if (mWindowAnimationBackgroundSurface != null) {
+            mWindowAnimationBackgroundSurface.hide();
+        }
+
+        if (mInnerFields.mWallpaperMayChange) {
+            if (DEBUG_WALLPAPER) Slog.v(TAG,
+                    "Wallpaper may change!  Adjusting");
+            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
+        }
+
+        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+            if (DEBUG_WALLPAPER) Slog.v(TAG,
+                    "Wallpaper layer changed: assigning layers + relayout");
+            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
+            assignLayersLocked();
+        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
+            if (DEBUG_WALLPAPER) Slog.v(TAG,
+                    "Wallpaper visibility changed: relayout");
+            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
+        }
+
+        if (mFocusMayChange) {
+            mFocusMayChange = false;
+            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
+                    false /*updateInputWindows*/)) {
+                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
+                mInnerFields.mAdjResult = 0;
+            }
+        }
+
+        return changes;
+    }
+
+    /**
+     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
+     *
+     * @param w WindowState whos Surface is being prepared.
+     * @param recoveringMemory true if the caller will reclaim surface memory on error.
+     */
+    public void prepareSurfaceLocked(final WindowState w, final boolean recoveringMemory) {
+        // XXX NOTE: The logic here could be improved.  We have
+        // the decision about whether to resize a window separated
+        // from whether to hide the surface.  This can cause us to
+        // resize a surface even if we are going to hide it.  You
+        // can see this by (1) holding device in landscape mode on
+        // home screen; (2) tapping browser icon (device will rotate
+        // to landscape; (3) tap home.  The wallpaper will be resized
+        // in step 2 but then immediately hidden, causing us to
+        // have to resize and then redraw it again in step 3.  It
+        // would be nice to figure out how to avoid this, but it is
+        // difficult because we do need to resize surfaces in some
+        // cases while they are hidden such as when first showing a
+        // window.
+        boolean displayed = false;
+
+        w.computeShownFrameLocked();
+
+        int width, height;
+        if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
+            // for a scaled surface, we just want to use
+            // the requested size.
+            width  = w.mRequestedWidth;
+            height = w.mRequestedHeight;
+        } else {
+            width = w.mCompatFrame.width();
+            height = w.mCompatFrame.height();
+        }
+
+        if (width < 1) {
+            width = 1;
+        }
+        if (height < 1) {
+            height = 1;
+        }
+        final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
+        if (surfaceResized) {
+            w.mSurfaceW = width;
+            w.mSurfaceH = height;
+        }
+
+        if (w.mSurfaceX != w.mShownFrame.left
+                || w.mSurfaceY != w.mShownFrame.top) {
+            try {
+                if (SHOW_TRANSACTIONS) logSurface(w,
+                        "POS " + w.mShownFrame.left
+                        + ", " + w.mShownFrame.top, null);
+                w.mSurfaceX = w.mShownFrame.left;
+                w.mSurfaceY = w.mShownFrame.top;
+                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
+            } catch (RuntimeException e) {
+                Slog.w(TAG, "Error positioning surface of " + w
+                        + " pos=(" + w.mShownFrame.left
+                        + "," + w.mShownFrame.top + ")", e);
+                if (!recoveringMemory) {
+                    reclaimSomeSurfaceMemoryLocked(w, "position", true);
+                }
+            }
+        }
+
+        if (surfaceResized) {
+            try {
+                if (SHOW_TRANSACTIONS) logSurface(w,
+                        "SIZE " + width + "x" + height, null);
+                w.mSurfaceResized = true;
+                w.mSurface.setSize(width, height);
+            } catch (RuntimeException e) {
+                // If something goes wrong with the surface (such
+                // as running out of memory), don't take down the
+                // entire system.
+                Slog.e(TAG, "Error resizing surface of " + w
+                        + " size=(" + width + "x" + height + ")", e);
+                if (!recoveringMemory) {
+                    reclaimSomeSurfaceMemoryLocked(w, "size", true);
+                }
+            }
+        }
+
+        if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
+            w.mContentInsetsChanged |=
+                !w.mLastContentInsets.equals(w.mContentInsets);
+            w.mVisibleInsetsChanged |=
+                !w.mLastVisibleInsets.equals(w.mVisibleInsets);
+            boolean configChanged =
+                w.mConfiguration != mCurConfiguration
+                && (w.mConfiguration == null
+                        || mCurConfiguration.diff(w.mConfiguration) != 0);
+            if (DEBUG_CONFIGURATION && configChanged) {
+                Slog.v(TAG, "Win " + w + " config changed: "
+                        + mCurConfiguration);
+            }
+            if (localLOGV) Slog.v(TAG, "Resizing " + w
+                    + ": configChanged=" + configChanged
+                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
+            w.mLastFrame.set(w.mFrame);
+            if (w.mContentInsetsChanged
+                    || w.mVisibleInsetsChanged
+                    || w.mSurfaceResized
+                    || configChanged) {
+                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
+                    Slog.v(TAG, "Resize reasons: "
+                            + " contentInsetsChanged=" + w.mContentInsetsChanged
+                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
+                            + " surfaceResized=" + w.mSurfaceResized
+                            + " configChanged=" + configChanged);
+                }
+
+                w.mLastContentInsets.set(w.mContentInsets);
+                w.mLastVisibleInsets.set(w.mVisibleInsets);
+                makeWindowFreezingScreenIfNeededLocked(w);
+                // If the orientation is changing, then we need to
+                // hold off on unfreezing the display until this
+                // window has been redrawn; to do that, we need
+                // to go through the process of getting informed
+                // by the application when it has finished drawing.
+                if (w.mOrientationChanging) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation start waiting for draw in "
+                            + w + ", surface " + w.mSurface);
+                    w.mDrawPending = true;
+                    w.mCommitDrawPending = false;
+                    w.mReadyToShow = false;
+                    if (w.mAppToken != null) {
+                        w.mAppToken.allDrawn = false;
+                    }
+                }
+                if (!mResizingWindows.contains(w)) {
+                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Resizing window " + w + " to " + w.mSurfaceW
+                            + "x" + w.mSurfaceH);
+                    mResizingWindows.add(w);
+                }
+            } else if (w.mOrientationChanging) {
+                if (!w.mDrawPending && !w.mCommitDrawPending) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation not waiting for draw in "
+                            + w + ", surface " + w.mSurface);
+                    w.mOrientationChanging = false;
+                }
+            }
+        }
+
+        if (w.mAttachedHidden || !w.isReadyForDisplay()) {
+            if (!w.mLastHidden) {
+                //dump();
+                w.mLastHidden = true;
+                if (SHOW_TRANSACTIONS) logSurface(w,
+                        "HIDE (performLayout)", null);
+                if (w.mSurface != null) {
+                    w.mSurfaceShown = false;
+                    try {
+                        w.mSurface.hide();
+                    } catch (RuntimeException e) {
+                        Slog.w(TAG, "Exception hiding surface in " + w);
+                    }
+                }
+            }
+            // If we are waiting for this window to handle an
+            // orientation change, well, it is hidden, so
+            // doesn't really matter.  Note that this does
+            // introduce a potential glitch if the window
+            // becomes unhidden before it has drawn for the
+            // new orientation.
+            if (w.mOrientationChanging) {
+                w.mOrientationChanging = false;
+                if (DEBUG_ORIENTATION) Slog.v(TAG,
+                        "Orientation change skips hidden " + w);
+            }
+        } else if (w.mLastLayer != w.mAnimLayer
+                || w.mLastAlpha != w.mShownAlpha
+                || w.mLastDsDx != w.mDsDx
+                || w.mLastDtDx != w.mDtDx
+                || w.mLastDsDy != w.mDsDy
+                || w.mLastDtDy != w.mDtDy
+                || w.mLastHScale != w.mHScale
+                || w.mLastVScale != w.mVScale
+                || w.mLastHidden) {
+            displayed = true;
+            w.mLastAlpha = w.mShownAlpha;
+            w.mLastLayer = w.mAnimLayer;
+            w.mLastDsDx = w.mDsDx;
+            w.mLastDtDx = w.mDtDx;
+            w.mLastDsDy = w.mDsDy;
+            w.mLastDtDy = w.mDtDy;
+            w.mLastHScale = w.mHScale;
+            w.mLastVScale = w.mVScale;
+            if (SHOW_TRANSACTIONS) logSurface(w,
+                    "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
+                    + " matrix=[" + (w.mDsDx*w.mHScale)
+                    + "," + (w.mDtDx*w.mVScale)
+                    + "][" + (w.mDsDy*w.mHScale)
+                    + "," + (w.mDtDy*w.mVScale) + "]", null);
+            if (w.mSurface != null) {
+                try {
+                    w.mSurfaceAlpha = w.mShownAlpha;
+                    w.mSurface.setAlpha(w.mShownAlpha);
+                    w.mSurfaceLayer = w.mAnimLayer;
+                    w.mSurface.setLayer(w.mAnimLayer);
+                    w.mSurface.setMatrix(
+                            w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
+                            w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
+                } catch (RuntimeException e) {
+                    Slog.w(TAG, "Error updating surface in " + w, e);
+                    if (!recoveringMemory) {
+                        reclaimSomeSurfaceMemoryLocked(w, "update", true);
+                    }
+                }
+            }
+
+            if (w.mLastHidden && !w.mDrawPending
+                    && !w.mCommitDrawPending
+                    && !w.mReadyToShow) {
+                if (SHOW_TRANSACTIONS) logSurface(w,
+                        "SHOW (performLayout)", null);
+                if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
+                        + " during relayout");
+                if (showSurfaceRobustlyLocked(w)) {
+                    w.mHasDrawn = true;
+                    w.mLastHidden = false;
+                } else {
+                    w.mOrientationChanging = false;
+                }
+            }
+            if (w.mSurface != null) {
+                w.mToken.hasVisible = true;
+            }
+        } else {
+            displayed = true;
+        }
+
+        if (displayed) {
+            if (w.mOrientationChanging) {
+                if (w.mDrawPending || w.mCommitDrawPending) {
+                    mInnerFields.mOrientationChangeComplete = false;
+                    if (DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation continue waiting for draw in " + w);
+                } else {
+                    w.mOrientationChanging = false;
+                    if (DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation change complete in " + w);
+                }
+            }
+            w.mToken.hasVisible = true;
+        }
+    }
+
+    /**
+     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
+     *
+     * @param w WindowState this method is applied to.
+     * @param currentTime The time which animations use for calculating transitions.
+     * @param innerDw Width of app window.
+     * @param innerDh Height of app window.
+     */
+    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
+                                         final int innerDw, final int innerDh) {
+        final WindowManager.LayoutParams attrs = w.mAttrs;
+        final int attrFlags = attrs.flags;
+        final boolean canBeSeen = w.isDisplayedLw();
+
+        if (w.mSurface != null) {
+            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
+                mInnerFields.mHoldScreen = w.mSession;
+            }
+            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
+                    && mInnerFields.mScreenBrightness < 0) {
+                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
+            }
+            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
+                    && mInnerFields.mButtonBrightness < 0) {
+                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
+            }
+            if (canBeSeen
+                    && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
+                     || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
+                     || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
+                mInnerFields.mSyswin = true;
+            }
+        }
+
+        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
+        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
+            // This window completely covers everything behind it,
+            // so we want to leave all of them as unblurred (for
+            // performance reasons).
+            mInnerFields.mObscured = true;
+        } else if (canBeSeen && (attrFlags & FLAG_BLUR_BEHIND | FLAG_DIM_BEHIND) != 0) {
+            if (localLOGV) Slog.v(TAG, "Win " + w
+                    + ": blurring=" + mInnerFields.mBlurring
+                    + " obscured=" + mInnerFields.mObscured);
+            if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
+                if (!mInnerFields.mDimming) {
+                    //Slog.i(TAG, "DIM BEHIND: " + w);
+                    mInnerFields.mDimming = true;
+                    if (mDimAnimator == null) {
+                        mDimAnimator = new DimAnimator(mFxSession);
+                    }
+                    mDimAnimator.show(innerDw, innerDh);
+                    mDimAnimator.updateParameters(mContext.getResources(),
+                            w, currentTime);
+                }
+            }
+            if ((attrFlags & FLAG_BLUR_BEHIND) != 0) {
+                if (!mInnerFields.mBlurring) {
+                    //Slog.i(TAG, "BLUR BEHIND: " + w);
+                    mInnerFields.mBlurring = true;
+                    if (mBlurSurface == null) {
+                        try {
+                            mBlurSurface = new Surface(mFxSession, 0,
+                                    "BlurSurface",
+                                    -1, 16, 16,
+                                    PixelFormat.OPAQUE,
+                                    Surface.FX_SURFACE_BLUR);
+                        } catch (Exception e) {
+                            Slog.e(TAG, "Exception creating Blur surface", e);
+                        }
+                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
+                                + mBlurSurface + ": CREATE");
+                    }
+                    final int dw = mCurDisplayWidth;
+                    final int dh = mCurDisplayHeight;
+                    if (mBlurSurface != null) {
+                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
+                                + mBlurSurface + ": pos=(0,0) (" +
+                                dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
+                        mBlurSurface.setPosition(0, 0);
+                        mBlurSurface.setSize(dw, dh);
+                        mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR);
+                        if (!mBlurShown) {
+                            try {
+                                if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
+                                        + mBlurSurface + ": SHOW");
+                                mBlurSurface.show();
+                            } catch (RuntimeException e) {
+                                Slog.w(TAG, "Failure showing blur surface", e);
+                            }
+                            mBlurShown = true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     // "Something has changed!  Let's make it correct now."
     private final void performLayoutAndPlaceSurfacesLockedInner(
             boolean recoveringMemory) {
@@ -7573,15 +8636,14 @@
             mExitingAppTokens.get(i).hasVisible = false;
         }
 
-        boolean orientationChangeComplete = true;
-        Session holdScreen = null;
-        float screenBrightness = -1;
-        float buttonBrightness = -1;
+        mInnerFields.mOrientationChangeComplete = true;
+        mInnerFields.mHoldScreen = null;
+        mInnerFields.mScreenBrightness = -1;
+        mInnerFields.mButtonBrightness = -1;
         boolean focusDisplayed = false;
-        boolean animating = false;
+        mInnerFields.mAnimating = false;
         boolean createWatermark = false;
         boolean updateRotation = false;
-        boolean screenRotationFinished = false;
 
         if (mFxSession == null) {
             mFxSession = new SurfaceSession();
@@ -7604,7 +8666,7 @@
         }
 
         try {
-            boolean wallpaperForceHidingChanged = false;
+            mInnerFields.mWallpaperForceHidingChanged = false;
             int repeats = 0;
             int changes = 0;
             
@@ -7615,655 +8677,93 @@
                     mLayoutNeeded = false;
                     break;
                 }
-                
-                if ((changes&(WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER
-                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG
-                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) {
-                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
-                        if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
-                            assignLayersLocked();
-                            mLayoutNeeded = true;
-                        }
-                    }
-                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
-                        if (updateOrientationFromAppTokensLocked(true)) {
-                            mLayoutNeeded = true;
-                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-                        }
-                    }
-                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+
+                if ((changes & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+                    if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+                        assignLayersLocked();
                         mLayoutNeeded = true;
                     }
                 }
-                
+                if ((changes & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
+                    if (updateOrientationFromAppTokensLocked(true)) {
+                        mLayoutNeeded = true;
+                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+                    }
+                }
+                if ((changes & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+                    mLayoutNeeded = true;
+                }
+
                 // FIRST LOOP: Perform a layout, if needed.
                 if (repeats < 4) {
-                    changes = performLayoutLockedInner(repeats == 0, false /*updateInputWindows*/);
-                    if (changes != 0) {
-                        continue;
-                    }
+                    performLayoutLockedInner(repeats == 0, false /*updateInputWindows*/);
                 } else {
                     Slog.w(TAG, "Layout repeat skipped after too many iterations");
-                    changes = 0;
                 }
-                
-                final int transactionSequence = ++mTransactionSequence;
+
+                changes = 0;
+                ++mTransactionSequence;
 
                 // Update animations of all applications, including those
                 // associated with exiting/removed apps
-                boolean tokensAnimating = false;
-                final int NAT = mAppTokens.size();
-                for (i=0; i<NAT; i++) {
-                    if (mAppTokens.get(i).stepAnimationLocked(currentTime,
-                            innerDw, innerDh)) {
-                        tokensAnimating = true;
-                    }
-                }
-                final int NEAT = mExitingAppTokens.size();
-                for (i=0; i<NEAT; i++) {
-                    if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime,
-                            innerDw, innerDh)) {
-                        tokensAnimating = true;
-                    }
-                }
+                mInnerFields.mAnimating = false;
 
                 // SECOND LOOP: Execute animations and update visibility of windows.
-                
+                updateRotation |=
+                        updateAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh);
+
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
-                        + transactionSequence + " tokensAnimating="
-                        + tokensAnimating);
-                        
-                animating = tokensAnimating;
+                        + mTransactionSequence + " mAnimating="
+                        + mInnerFields.mAnimating);
 
-                if (mScreenRotationAnimation != null) {
-                    if (mScreenRotationAnimation.isAnimating()) {
-                        if (mScreenRotationAnimation.stepAnimation(currentTime)) {
-                            animating = true;
-                        } else {
-                            screenRotationFinished = true;
-                            updateRotation = true;
-                        }
-                    }
-                }
-
-                boolean tokenMayBeDrawn = false;
-                boolean wallpaperMayChange = false;
-                boolean forceHiding = false;
-                WindowState windowDetachedWallpaper = null;
-                WindowState windowAnimationBackground = null;
-                int windowAnimationBackgroundColor = 0;
+                mInnerFields.mTokenMayBeDrawn = false;
+                mInnerFields.mWallpaperMayChange = false;
+                mInnerFields.mForceHiding = false;
+                mInnerFields.mDetachedWallpaper = null;
+                mInnerFields.mWindowAnimationBackground = null;
+                mInnerFields.mWindowAnimationBackgroundColor = 0;
 
                 mPolicy.beginAnimationLw(dw, dh);
 
-                final int N = mWindows.size();
-
-                for (i=N-1; i>=0; i--) {
-                    WindowState w = mWindows.get(i);
-
-                    final WindowManager.LayoutParams attrs = w.mAttrs;
-
-                    if (w.mSurface != null) {
-                        // Take care of the window being ready to display.
-                        if (w.commitFinishDrawingLocked(currentTime)) {
-                            if ((w.mAttrs.flags
-                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
-                                if (DEBUG_WALLPAPER) Slog.v(TAG,
-                                        "First draw done in potential wallpaper target " + w);
-                                wallpaperMayChange = true;
-                            }
-                        }
-
-                        final boolean wasAnimating = w.mAnimating;
-
-                        int animDw = innerDw;
-                        int animDh = innerDh;
-
-                        // If the window has moved due to its containing
-                        // content frame changing, then we'd like to animate
-                        // it.  The checks here are ordered by what is least
-                        // likely to be true first.
-                        if (w.shouldAnimateMove()) {
-                            // Frame has moved, containing content frame
-                            // has also moved, and we're not currently animating...
-                            // let's do something.
-                            Animation a = AnimationUtils.loadAnimation(mContext,
-                                    com.android.internal.R.anim.window_move_from_decor);
-                            w.setAnimation(a);
-                            animDw = w.mLastFrame.left - w.mFrame.left;
-                            animDh = w.mLastFrame.top - w.mFrame.top;
-                        }
-
-                        // Execute animation.
-                        final boolean nowAnimating = w.stepAnimationLocked(currentTime,
-                                animDw, animDh);
-
-                        // If this window is animating, make a note that we have
-                        // an animating window and take care of a request to run
-                        // a detached wallpaper animation.
-                        if (nowAnimating) {
-                            if (w.mAnimation != null) {
-                                if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
-                                        && w.mAnimation.getDetachWallpaper()) {
-                                    windowDetachedWallpaper = w;
-                                }
-                                if (w.mAnimation.getBackgroundColor() != 0) {
-                                    if (windowAnimationBackground == null || w.mAnimLayer <
-                                            windowAnimationBackground.mAnimLayer) {
-                                        windowAnimationBackground = w;
-                                        windowAnimationBackgroundColor =
-                                                w.mAnimation.getBackgroundColor();
-                                    }
-                                }
-                            }
-                            animating = true;
-                        }
-
-                        // If this window's app token is running a detached wallpaper
-                        // animation, make a note so we can ensure the wallpaper is
-                        // displayed behind it.
-                        if (w.mAppToken != null && w.mAppToken.animation != null
-                                && w.mAppToken.animating) {
-                            if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
-                                    && w.mAppToken.animation.getDetachWallpaper()) {
-                                windowDetachedWallpaper = w;
-                            }
-                            if (w.mAppToken.animation.getBackgroundColor() != 0) {
-                                if (windowAnimationBackground == null || w.mAnimLayer <
-                                        windowAnimationBackground.mAnimLayer) {
-                                    windowAnimationBackground = w;
-                                    windowAnimationBackgroundColor =
-                                            w.mAppToken.animation.getBackgroundColor();
-                                }
-                            }
-                        }
-
-                        if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
-                            wallpaperMayChange = true;
-                        }
-
-                        if (mPolicy.doesForceHide(w, attrs)) {
-                            if (!wasAnimating && nowAnimating) {
-                                if (DEBUG_VISIBILITY) Slog.v(TAG,
-                                        "Animation started that could impact force hide: "
-                                        + w);
-                                wallpaperForceHidingChanged = true;
-                                mFocusMayChange = true;
-                            } else if (w.isReadyForDisplay() && w.mAnimation == null) {
-                                forceHiding = true;
-                            }
-                        } else if (mPolicy.canBeForceHidden(w, attrs)) {
-                            boolean changed;
-                            if (forceHiding) {
-                                changed = w.hideLw(false, false);
-                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                        "Now policy hidden: " + w);
-                            } else {
-                                changed = w.showLw(false, false);
-                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                        "Now policy shown: " + w);
-                                if (changed) {
-                                    if (wallpaperForceHidingChanged
-                                            && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
-                                        // Assume we will need to animate.  If
-                                        // we don't (because the wallpaper will
-                                        // stay with the lock screen), then we will
-                                        // clean up later.
-                                        Animation a = mPolicy.createForceHideEnterAnimation();
-                                        if (a != null) {
-                                            w.setAnimation(a);
-                                        }
-                                    }
-                                    if (mCurrentFocus == null ||
-                                            mCurrentFocus.mLayer < w.mLayer) {
-                                        // We are showing on to of the current
-                                        // focus, so re-evaluate focus to make
-                                        // sure it is correct.
-                                        mFocusMayChange = true;
-                                    }
-                                }
-                            }
-                            if (changed && (attrs.flags
-                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
-                                wallpaperMayChange = true;
-                            }
-                        }
-
-                        mPolicy.animatingWindowLw(w, attrs);
-                    }
-
-                    final AppWindowToken atoken = w.mAppToken;
-                    if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
-                        if (atoken.lastTransactionSequence != transactionSequence) {
-                            atoken.lastTransactionSequence = transactionSequence;
-                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
-                            atoken.startingDisplayed = false;
-                        }
-                        if ((w.isOnScreen() || w.mAttrs.type
-                                == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
-                                && !w.mExiting && !w.mDestroying) {
-                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
-                                Slog.v(TAG, "Eval win " + w + ": isDrawn="
-                                        + w.isDrawnLw()
-                                        + ", isAnimating=" + w.isAnimating());
-                                if (!w.isDrawnLw()) {
-                                    Slog.v(TAG, "Not displayed: s=" + w.mSurface
-                                            + " pv=" + w.mPolicyVisibility
-                                            + " dp=" + w.mDrawPending
-                                            + " cdp=" + w.mCommitDrawPending
-                                            + " ah=" + w.mAttachedHidden
-                                            + " th=" + atoken.hiddenRequested
-                                            + " a=" + w.mAnimating);
-                                }
-                            }
-                            if (w != atoken.startingWindow) {
-                                if (!atoken.freezingScreen || !w.mAppFreezing) {
-                                    atoken.numInterestingWindows++;
-                                    if (w.isDrawnLw()) {
-                                        atoken.numDrawnWindows++;
-                                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
-                                                "tokenMayBeDrawn: " + atoken
-                                                + " freezingScreen=" + atoken.freezingScreen
-                                                + " mAppFreezing=" + w.mAppFreezing);
-                                        tokenMayBeDrawn = true;
-                                    }
-                                }
-                            } else if (w.isDrawnLw()) {
-                                atoken.startingDisplayed = true;
-                            }
-                        }
-                    } else if (w.mReadyToShow) {
-                        w.performShowLocked();
-                    }
-                }
+                updateWindowsAndWallpaperLocked(currentTime, innerDw, innerDh);
 
                 changes |= mPolicy.finishAnimationLw();
 
-                if (tokenMayBeDrawn) {
-                    // See if any windows have been drawn, so they (and others
-                    // associated with them) can now be shown.
-                    final int NT = mAppTokens.size();
-                    for (i=0; i<NT; i++) {
-                        AppWindowToken wtoken = mAppTokens.get(i);
-                        if (wtoken.freezingScreen) {
-                            int numInteresting = wtoken.numInterestingWindows;
-                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                                if (DEBUG_VISIBILITY) Slog.v(TAG,
-                                        "allDrawn: " + wtoken
-                                        + " interesting=" + numInteresting
-                                        + " drawn=" + wtoken.numDrawnWindows);
-                                wtoken.showAllWindowsLocked();
-                                unsetAppFreezingScreenLocked(wtoken, false, true);
-                                if (DEBUG_ORIENTATION) Slog.i(TAG,
-                                        "Setting orientationChangeComplete=true because wtoken "
-                                        + wtoken + " numInteresting=" + numInteresting
-                                        + " numDrawn=" + wtoken.numDrawnWindows);
-                                orientationChangeComplete = true;
-                            }
-                        } else if (!wtoken.allDrawn) {
-                            int numInteresting = wtoken.numInterestingWindows;
-                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                                if (DEBUG_VISIBILITY) Slog.v(TAG,
-                                        "allDrawn: " + wtoken
-                                        + " interesting=" + numInteresting
-                                        + " drawn=" + wtoken.numDrawnWindows);
-                                wtoken.allDrawn = true;
-                                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
-
-                                // We can now show all of the drawn windows!
-                                if (!mOpeningApps.contains(wtoken)) {
-                                    wtoken.showAllWindowsLocked();
-                                }
-                            }
-                        }
-                    }
+                if (mInnerFields.mTokenMayBeDrawn) {
+                    changes |= testTokenMayBeDrawnLocked();
                 }
 
                 // If we are ready to perform an app transition, check through
                 // all of the app tokens to be shown and see if they are ready
                 // to go.
                 if (mAppTransitionReady) {
-                    int NN = mOpeningApps.size();
-                    boolean goodToGo = true;
-                    if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                            "Checking " + NN + " opening apps (frozen="
-                            + mDisplayFrozen + " timeout="
-                            + mAppTransitionTimeout + ")...");
-                    if (!mDisplayFrozen && !mAppTransitionTimeout) {
-                        // If the display isn't frozen, wait to do anything until
-                        // all of the apps are ready.  Otherwise just go because
-                        // we'll unfreeze the display when everyone is ready.
-                        for (i=0; i<NN && goodToGo; i++) {
-                            AppWindowToken wtoken = mOpeningApps.get(i);
-                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                                    "Check opening app" + wtoken + ": allDrawn="
-                                    + wtoken.allDrawn + " startingDisplayed="
-                                    + wtoken.startingDisplayed);
-                            if (!wtoken.allDrawn && !wtoken.startingDisplayed
-                                    && !wtoken.startingMoved) {
-                                goodToGo = false;
-                            }
-                        }
-                    }
-                    if (goodToGo) {
-                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
-                        int transit = mNextAppTransition;
-                        if (mSkipAppTransitionAnimation) {
-                            transit = WindowManagerPolicy.TRANSIT_UNSET;
-                        }
-                        mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
-                        mAppTransitionReady = false;
-                        mAppTransitionRunning = true;
-                        mAppTransitionTimeout = false;
-                        mStartingIconInTransition = false;
-                        mSkipAppTransitionAnimation = false;
-
-                        mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
-
-                        // If there are applications waiting to come to the
-                        // top of the stack, now is the time to move their windows.
-                        // (Note that we don't do apps going to the bottom
-                        // here -- we want to keep their windows in the old
-                        // Z-order until the animation completes.)
-                        if (mToTopApps.size() > 0) {
-                            NN = mAppTokens.size();
-                            for (i=0; i<NN; i++) {
-                                AppWindowToken wtoken = mAppTokens.get(i);
-                                if (wtoken.sendingToTop) {
-                                    wtoken.sendingToTop = false;
-                                    moveAppWindowsLocked(wtoken, NN, false);
-                                }
-                            }
-                            mToTopApps.clear();
-                        }
-
-                        WindowState oldWallpaper = mWallpaperTarget;
-
-                        adjustWallpaperWindowsLocked();
-                        wallpaperMayChange = false;
-
-                        // The top-most window will supply the layout params,
-                        // and we will determine it below.
-                        LayoutParams animLp = null;
-                        int bestAnimLayer = -1;
-                        boolean fullscreenAnim = false;
-
-                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                                "New wallpaper target=" + mWallpaperTarget
-                                + ", lower target=" + mLowerWallpaperTarget
-                                + ", upper target=" + mUpperWallpaperTarget);
-                        int foundWallpapers = 0;
-                        // Do a first pass through the tokens for two
-                        // things:
-                        // (1) Determine if both the closing and opening
-                        // app token sets are wallpaper targets, in which
-                        // case special animations are needed
-                        // (since the wallpaper needs to stay static
-                        // behind them).
-                        // (2) Find the layout params of the top-most
-                        // application window in the tokens, which is
-                        // what will control the animation theme.
-                        final int NC = mClosingApps.size();
-                        NN = NC + mOpeningApps.size();
-                        for (i=0; i<NN; i++) {
-                            AppWindowToken wtoken;
-                            int mode;
-                            if (i < NC) {
-                                wtoken = mClosingApps.get(i);
-                                mode = 1;
-                            } else {
-                                wtoken = mOpeningApps.get(i-NC);
-                                mode = 2;
-                            }
-                            if (mLowerWallpaperTarget != null) {
-                                if (mLowerWallpaperTarget.mAppToken == wtoken
-                                        || mUpperWallpaperTarget.mAppToken == wtoken) {
-                                    foundWallpapers |= mode;
-                                }
-                            }
-                            if (wtoken.appFullscreen) {
-                                WindowState ws = wtoken.findMainWindow();
-                                if (ws != null) {
-                                    animLp = ws.mAttrs;
-                                    bestAnimLayer = ws.mLayer;
-                                    fullscreenAnim = true;
-                                }
-                            } else if (!fullscreenAnim) {
-                                WindowState ws = wtoken.findMainWindow();
-                                if (ws != null) {
-                                    if (ws.mLayer > bestAnimLayer) {
-                                        animLp = ws.mAttrs;
-                                        bestAnimLayer = ws.mLayer;
-                                    }
-                                }
-                            }
-                        }
-
-                        if (foundWallpapers == 3) {
-                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                                    "Wallpaper animation!");
-                            switch (transit) {
-                                case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
-                                case WindowManagerPolicy.TRANSIT_TASK_OPEN:
-                                case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
-                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
-                                    break;
-                                case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
-                                case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
-                                case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
-                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
-                                    break;
-                            }
-                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                                    "New transit: " + transit);
-                        } else if (oldWallpaper != null) {
-                            // We are transitioning from an activity with
-                            // a wallpaper to one without.
-                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
-                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                                    "New transit away from wallpaper: " + transit);
-                        } else if (mWallpaperTarget != null) {
-                            // We are transitioning from an activity without
-                            // a wallpaper to now showing the wallpaper
-                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
-                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                                    "New transit into wallpaper: " + transit);
-                        }
-
-                        // If all closing windows are obscured, then there is
-                        // no need to do an animation.  This is the case, for
-                        // example, when this transition is being done behind
-                        // the lock screen.
-                        if (!mPolicy.allowAppAnimationsLw()) {
-                            animLp = null;
-                        }
-                        
-                        NN = mOpeningApps.size();
-                        for (i=0; i<NN; i++) {
-                            AppWindowToken wtoken = mOpeningApps.get(i);
-                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                                    "Now opening app" + wtoken);
-                            wtoken.reportedVisible = false;
-                            wtoken.inPendingTransaction = false;
-                            wtoken.animation = null;
-                            setTokenVisibilityLocked(wtoken, animLp, true,
-                                    transit, false);
-                            wtoken.updateReportedVisibilityLocked();
-                            wtoken.waitingToShow = false;
-                            wtoken.showAllWindowsLocked();
-                        }
-                        NN = mClosingApps.size();
-                        for (i=0; i<NN; i++) {
-                            AppWindowToken wtoken = mClosingApps.get(i);
-                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                                    "Now closing app" + wtoken);
-                            wtoken.inPendingTransaction = false;
-                            wtoken.animation = null;
-                            setTokenVisibilityLocked(wtoken, animLp, false,
-                                    transit, false);
-                            wtoken.updateReportedVisibilityLocked();
-                            wtoken.waitingToHide = false;
-                            // Force the allDrawn flag, because we want to start
-                            // this guy's animations regardless of whether it's
-                            // gotten drawn.
-                            wtoken.allDrawn = true;
-                        }
-
-                        mNextAppTransitionPackage = null;
-
-                        mOpeningApps.clear();
-                        mClosingApps.clear();
-
-                        // This has changed the visibility of windows, so perform
-                        // a new layout to get them all up-to-date.
-                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
-                                | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-                        mLayoutNeeded = true;
-                        if (!moveInputMethodWindowsIfNeededLocked(true)) {
-                            assignLayersLocked();
-                        }
-                        updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
-                                false /*updateInputWindows*/);
-                        mFocusMayChange = false;
-                    }
+                    changes |= handleAppTransitionReadyLocked();
                 }
 
-                int adjResult = 0;
+                mInnerFields.mAdjResult = 0;
 
-                if (!animating && mAppTransitionRunning) {
+                if (!mInnerFields.mAnimating && mAppTransitionRunning) {
                     // We have finished the animation of an app transition.  To do
                     // this, we have delayed a lot of operations like showing and
                     // hiding apps, moving apps in Z-order, etc.  The app token list
                     // reflects the correct Z-order, but the window list may now
                     // be out of sync with it.  So here we will just rebuild the
                     // entire app window list.  Fun!
-                    mAppTransitionRunning = false;
-                    // Clear information about apps that were moving.
-                    mToBottomApps.clear();
-
-                    rebuildAppWindowListLocked();
-                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
-                    adjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
-                    moveInputMethodWindowsIfNeededLocked(false);
-                    wallpaperMayChange = true;
-                    // Since the window list has been rebuilt, focus might
-                    // have to be recomputed since the actual order of windows
-                    // might have changed again.
-                    mFocusMayChange = true;
+                    changes |= handleAnimatingAndTransitionLocked();
                 }
 
-                if (wallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
+                if (mInnerFields.mWallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
                     // At this point, there was a window with a wallpaper that
                     // was force hiding other windows behind it, but now it
                     // is going away.  This may be simple -- just animate
                     // away the wallpaper and its window -- or it may be
                     // hard -- the wallpaper now needs to be shown behind
                     // something that was hidden.
-                    WindowState oldWallpaper = mWallpaperTarget;
-                    if (mLowerWallpaperTarget != null
-                            && mLowerWallpaperTarget.mAppToken != null) {
-                        if (DEBUG_WALLPAPER) Slog.v(TAG,
-                                "wallpaperForceHiding changed with lower="
-                                + mLowerWallpaperTarget);
-                        if (DEBUG_WALLPAPER) Slog.v(TAG,
-                                "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
-                                " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
-                        if (mLowerWallpaperTarget.mAppToken.hidden) {
-                            // The lower target has become hidden before we
-                            // actually started the animation...  let's completely
-                            // re-evaluate everything.
-                            mLowerWallpaperTarget = mUpperWallpaperTarget = null;
-                            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
-                        }
-                    }
-                    adjResult |= adjustWallpaperWindowsLocked();
-                    wallpaperMayChange = false;
-                    wallpaperForceHidingChanged = false;
-                    if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
-                            + " NEW: " + mWallpaperTarget
-                            + " LOWER: " + mLowerWallpaperTarget);
-                    if (mLowerWallpaperTarget == null) {
-                        // Whoops, we don't need a special wallpaper animation.
-                        // Clear them out.
-                        forceHiding = false;
-                        for (i=N-1; i>=0; i--) {
-                            WindowState w = mWindows.get(i);
-                            if (w.mSurface != null) {
-                                final WindowManager.LayoutParams attrs = w.mAttrs;
-                                if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
-                                    if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
-                                    forceHiding = true;
-                                } else if (mPolicy.canBeForceHidden(w, attrs)) {
-                                    if (!w.mAnimating) {
-                                        // We set the animation above so it
-                                        // is not yet running.
-                                        w.clearAnimation();
-                                    }
-                                }
-                            }
-                        }
-                    }
+                    changes |= animateAwayWallpaperLocked();
                 }
 
-                if (mWindowDetachedWallpaper != windowDetachedWallpaper) {
-                    if (DEBUG_WALLPAPER) Slog.v(TAG,
-                            "Detached wallpaper changed from " + mWindowDetachedWallpaper
-                            + " to " + windowDetachedWallpaper);
-                    mWindowDetachedWallpaper = windowDetachedWallpaper;
-                    wallpaperMayChange = true;
-                }
-
-                if (windowAnimationBackgroundColor != 0) {
-                    // If the window that wants black is the current wallpaper
-                    // target, then the black goes *below* the wallpaper so we
-                    // don't cause the wallpaper to suddenly disappear.
-                    WindowState target = windowAnimationBackground;
-                    if (mWallpaperTarget == windowAnimationBackground
-                            || mLowerWallpaperTarget == windowAnimationBackground
-                            || mUpperWallpaperTarget == windowAnimationBackground) {
-                        for (i=0; i<mWindows.size(); i++) {
-                            WindowState w = mWindows.get(i);
-                            if (w.mIsWallpaper) {
-                                target = w;
-                                break;
-                            }
-                        }
-                    }
-                    if (mWindowAnimationBackgroundSurface == null) {
-                        mWindowAnimationBackgroundSurface = new DimSurface(mFxSession);
-                    }
-                    mWindowAnimationBackgroundSurface.show(dw, dh,
-                            target.mAnimLayer - LAYER_OFFSET_DIM,
-                            windowAnimationBackgroundColor);
-                } else if (mWindowAnimationBackgroundSurface != null) {
-                    mWindowAnimationBackgroundSurface.hide();
-                }
-
-                if (wallpaperMayChange) {
-                    if (DEBUG_WALLPAPER) Slog.v(TAG,
-                            "Wallpaper may change!  Adjusting");
-                    adjResult |= adjustWallpaperWindowsLocked();
-                }
-
-                if ((adjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
-                    if (DEBUG_WALLPAPER) Slog.v(TAG,
-                            "Wallpaper layer changed: assigning layers + relayout");
-                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
-                    assignLayersLocked();
-                } else if ((adjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
-                    if (DEBUG_WALLPAPER) Slog.v(TAG,
-                            "Wallpaper visibility changed: relayout");
-                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
-                }
-
-                if (mFocusMayChange) {
-                    mFocusMayChange = false;
-                    if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
-                            false /*updateInputWindows*/)) {
-                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
-                        adjResult = 0;
-                    }
-                }
+                changes |= testWallpaperAndBackgroundLocked();
 
                 if (mLayoutNeeded) {
                     changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
@@ -8277,278 +8777,22 @@
 
             final boolean someoneLosingFocus = mLosingFocus.size() != 0;
 
-            boolean obscured = false;
-            boolean blurring = false;
-            boolean dimming = false;
-            boolean covered = false;
-            boolean syswin = false;
+            mInnerFields.mObscured = false;
+            mInnerFields.mBlurring = false;
+            mInnerFields.mDimming = false;
+            mInnerFields.mSyswin = false;
 
             final int N = mWindows.size();
 
             for (i=N-1; i>=0; i--) {
                 WindowState w = mWindows.get(i);
 
-                boolean displayed = false;
-                final WindowManager.LayoutParams attrs = w.mAttrs;
-                final int attrFlags = attrs.flags;
-
                 if (w.mSurface != null) {
-                    // XXX NOTE: The logic here could be improved.  We have
-                    // the decision about whether to resize a window separated
-                    // from whether to hide the surface.  This can cause us to
-                    // resize a surface even if we are going to hide it.  You
-                    // can see this by (1) holding device in landscape mode on
-                    // home screen; (2) tapping browser icon (device will rotate
-                    // to landscape; (3) tap home.  The wallpaper will be resized
-                    // in step 2 but then immediately hidden, causing us to
-                    // have to resize and then redraw it again in step 3.  It
-                    // would be nice to figure out how to avoid this, but it is
-                    // difficult because we do need to resize surfaces in some
-                    // cases while they are hidden such as when first showing a
-                    // window.
-                    
-                    w.computeShownFrameLocked();
-                    if (localLOGV) Slog.v(
-                            TAG, "Placing surface #" + i + " " + w.mSurface
-                            + ": new=" + w.mShownFrame);
-
-                    if (w.mSurface != null) {
-                        int width, height;
-                        if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
-                            // for a scaled surface, we just want to use
-                            // the requested size.
-                            width  = w.mRequestedWidth;
-                            height = w.mRequestedHeight;
-                        } else {
-                            width = w.mCompatFrame.width();
-                            height = w.mCompatFrame.height();
-                        }
-
-                        if (width < 1) {
-                            width = 1;
-                        }
-                        if (height < 1) {
-                            height = 1;
-                        }
-                        final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
-                        if (surfaceResized) {
-                            w.mSurfaceW = width;
-                            w.mSurfaceH = height;
-                        }
-
-                        if (w.mSurfaceX != w.mShownFrame.left
-                                || w.mSurfaceY != w.mShownFrame.top) {
-                            try {
-                                if (SHOW_TRANSACTIONS) logSurface(w,
-                                        "POS " + w.mShownFrame.left
-                                        + ", " + w.mShownFrame.top, null);
-                                w.mSurfaceX = w.mShownFrame.left;
-                                w.mSurfaceY = w.mShownFrame.top;
-                                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
-                            } catch (RuntimeException e) {
-                                Slog.w(TAG, "Error positioning surface of " + w
-                                        + " pos=(" + w.mShownFrame.left
-                                        + "," + w.mShownFrame.top + ")", e);
-                                if (!recoveringMemory) {
-                                    reclaimSomeSurfaceMemoryLocked(w, "position", true);
-                                }
-                            }
-                        }
-
-                        if (surfaceResized) {
-                            try {
-                                if (SHOW_TRANSACTIONS) logSurface(w,
-                                        "SIZE " + width + "x" + height, null);
-                                w.mSurfaceResized = true;
-                                w.mSurface.setSize(width, height);
-                            } catch (RuntimeException e) {
-                                // If something goes wrong with the surface (such
-                                // as running out of memory), don't take down the
-                                // entire system.
-                                Slog.e(TAG, "Error resizing surface of " + w
-                                        + " size=(" + width + "x" + height + ")", e);
-                                if (!recoveringMemory) {
-                                    reclaimSomeSurfaceMemoryLocked(w, "size", true);
-                                }
-                            }
-                        }
-                    }
-
-                    if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
-                        w.mContentInsetsChanged |=
-                            !w.mLastContentInsets.equals(w.mContentInsets);
-                        w.mVisibleInsetsChanged |=
-                            !w.mLastVisibleInsets.equals(w.mVisibleInsets);
-                        boolean configChanged =
-                            w.mConfiguration != mCurConfiguration
-                            && (w.mConfiguration == null
-                                    || mCurConfiguration.diff(w.mConfiguration) != 0);
-                        if (DEBUG_CONFIGURATION && configChanged) {
-                            Slog.v(TAG, "Win " + w + " config changed: "
-                                    + mCurConfiguration);
-                        }
-                        if (localLOGV) Slog.v(TAG, "Resizing " + w
-                                + ": configChanged=" + configChanged
-                                + " last=" + w.mLastFrame + " frame=" + w.mFrame);
-                        w.mLastFrame.set(w.mFrame);
-                        if (w.mContentInsetsChanged
-                                || w.mVisibleInsetsChanged
-                                || w.mSurfaceResized
-                                || configChanged) {
-                            if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
-                                Slog.v(TAG, "Resize reasons: "
-                                        + " contentInsetsChanged=" + w.mContentInsetsChanged
-                                        + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
-                                        + " surfaceResized=" + w.mSurfaceResized
-                                        + " configChanged=" + configChanged);
-                            }
-
-                            w.mLastContentInsets.set(w.mContentInsets);
-                            w.mLastVisibleInsets.set(w.mVisibleInsets);
-                            makeWindowFreezingScreenIfNeededLocked(w);
-                            // If the orientation is changing, then we need to
-                            // hold off on unfreezing the display until this
-                            // window has been redrawn; to do that, we need
-                            // to go through the process of getting informed
-                            // by the application when it has finished drawing.
-                            if (w.mOrientationChanging) {
-                                if (DEBUG_ORIENTATION) Slog.v(TAG,
-                                        "Orientation start waiting for draw in "
-                                        + w + ", surface " + w.mSurface);
-                                w.mDrawPending = true;
-                                w.mCommitDrawPending = false;
-                                w.mReadyToShow = false;
-                                if (w.mAppToken != null) {
-                                    w.mAppToken.allDrawn = false;
-                                }
-                            }
-                            if (!mResizingWindows.contains(w)) {
-                                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
-                                        "Resizing window " + w + " to " + w.mSurfaceW
-                                        + "x" + w.mSurfaceH);
-                                mResizingWindows.add(w);
-                            }
-                        } else if (w.mOrientationChanging) {
-                            if (!w.mDrawPending && !w.mCommitDrawPending) {
-                                if (DEBUG_ORIENTATION) Slog.v(TAG,
-                                        "Orientation not waiting for draw in "
-                                        + w + ", surface " + w.mSurface);
-                                w.mOrientationChanging = false;
-                            }
-                        }
-                    }
-
-                    if (w.mAttachedHidden || !w.isReadyForDisplay()) {
-                        if (!w.mLastHidden) {
-                            //dump();
-                            w.mLastHidden = true;
-                            if (SHOW_TRANSACTIONS) logSurface(w,
-                                    "HIDE (performLayout)", null);
-                            if (w.mSurface != null) {
-                                w.mSurfaceShown = false;
-                                try {
-                                    w.mSurface.hide();
-                                } catch (RuntimeException e) {
-                                    Slog.w(TAG, "Exception hiding surface in " + w);
-                                }
-                            }
-                        }
-                        // If we are waiting for this window to handle an
-                        // orientation change, well, it is hidden, so
-                        // doesn't really matter.  Note that this does
-                        // introduce a potential glitch if the window
-                        // becomes unhidden before it has drawn for the
-                        // new orientation.
-                        if (w.mOrientationChanging) {
-                            w.mOrientationChanging = false;
-                            if (DEBUG_ORIENTATION) Slog.v(TAG,
-                                    "Orientation change skips hidden " + w);
-                        }
-                    } else if (w.mLastLayer != w.mAnimLayer
-                            || w.mLastAlpha != w.mShownAlpha
-                            || w.mLastDsDx != w.mDsDx
-                            || w.mLastDtDx != w.mDtDx
-                            || w.mLastDsDy != w.mDsDy
-                            || w.mLastDtDy != w.mDtDy
-                            || w.mLastHScale != w.mHScale
-                            || w.mLastVScale != w.mVScale
-                            || w.mLastHidden) {
-                        displayed = true;
-                        w.mLastAlpha = w.mShownAlpha;
-                        w.mLastLayer = w.mAnimLayer;
-                        w.mLastDsDx = w.mDsDx;
-                        w.mLastDtDx = w.mDtDx;
-                        w.mLastDsDy = w.mDsDy;
-                        w.mLastDtDy = w.mDtDy;
-                        w.mLastHScale = w.mHScale;
-                        w.mLastVScale = w.mVScale;
-                        if (SHOW_TRANSACTIONS) logSurface(w,
-                                "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
-                                + " matrix=[" + (w.mDsDx*w.mHScale)
-                                + "," + (w.mDtDx*w.mVScale)
-                                + "][" + (w.mDsDy*w.mHScale)
-                                + "," + (w.mDtDy*w.mVScale) + "]", null);
-                        if (w.mSurface != null) {
-                            try {
-                                w.mSurfaceAlpha = w.mShownAlpha;
-                                w.mSurface.setAlpha(w.mShownAlpha);
-                                w.mSurfaceLayer = w.mAnimLayer;
-                                w.mSurface.setLayer(w.mAnimLayer);
-                                w.mSurface.setMatrix(
-                                        w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
-                                        w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
-                            } catch (RuntimeException e) {
-                                Slog.w(TAG, "Error updating surface in " + w, e);
-                                if (!recoveringMemory) {
-                                    reclaimSomeSurfaceMemoryLocked(w, "update", true);
-                                }
-                            }
-                        }
-
-                        if (w.mLastHidden && !w.mDrawPending
-                                && !w.mCommitDrawPending
-                                && !w.mReadyToShow) {
-                            if (SHOW_TRANSACTIONS) logSurface(w,
-                                    "SHOW (performLayout)", null);
-                            if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
-                                    + " during relayout");
-                            if (showSurfaceRobustlyLocked(w)) {
-                                w.mHasDrawn = true;
-                                w.mLastHidden = false;
-                            } else {
-                                w.mOrientationChanging = false;
-                            }
-                        }
-                        if (w.mSurface != null) {
-                            w.mToken.hasVisible = true;
-                        }
-                    } else {
-                        displayed = true;
-                    }
-
-                    if (displayed) {
-                        if (!covered) {
-                            if (attrs.width == LayoutParams.MATCH_PARENT
-                                    && attrs.height == LayoutParams.MATCH_PARENT) {
-                                covered = true;
-                            }
-                        }
-                        if (w.mOrientationChanging) {
-                            if (w.mDrawPending || w.mCommitDrawPending) {
-                                orientationChangeComplete = false;
-                                if (DEBUG_ORIENTATION) Slog.v(TAG,
-                                        "Orientation continue waiting for draw in " + w);
-                            } else {
-                                w.mOrientationChanging = false;
-                                if (DEBUG_ORIENTATION) Slog.v(TAG,
-                                        "Orientation change complete in " + w);
-                            }
-                        }
-                        w.mToken.hasVisible = true;
-                    }
+                    prepareSurfaceLocked(w, recoveringMemory);
                 } else if (w.mOrientationChanging) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Orientation change skips hidden " + w);
+                    if (DEBUG_ORIENTATION) {
+                        Slog.v(TAG, "Orientation change skips hidden " + w);
+                    }
                     w.mOrientationChanging = false;
                 }
 
@@ -8563,92 +8807,12 @@
                     focusDisplayed = true;
                 }
 
-                final boolean obscuredChanged = w.mObscured != obscured;
+                final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
 
                 // Update effect.
-                if (!(w.mObscured=obscured)) {
-                    if (w.mSurface != null) {
-                        if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
-                            holdScreen = w.mSession;
-                        }
-                        if (!syswin && w.mAttrs.screenBrightness >= 0
-                                && screenBrightness < 0) {
-                            screenBrightness = w.mAttrs.screenBrightness;
-                        }
-                        if (!syswin && w.mAttrs.buttonBrightness >= 0
-                                && buttonBrightness < 0) {
-                            buttonBrightness = w.mAttrs.buttonBrightness;
-                        }
-                        if (canBeSeen
-                                && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
-                                 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
-                                 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
-                            syswin = true;
-                        }
-                    }
-
-                    boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
-                    if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
-                        // This window completely covers everything behind it,
-                        // so we want to leave all of them as unblurred (for
-                        // performance reasons).
-                        obscured = true;
-                    } else if (canBeSeen && !obscured &&
-                            (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
-                        if (localLOGV) Slog.v(TAG, "Win " + w
-                                + ": blurring=" + blurring
-                                + " obscured=" + obscured
-                                + " displayed=" + displayed);
-                        if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
-                            if (!dimming) {
-                                //Slog.i(TAG, "DIM BEHIND: " + w);
-                                dimming = true;
-                                if (mDimAnimator == null) {
-                                    mDimAnimator = new DimAnimator(mFxSession);
-                                }
-                                mDimAnimator.show(innerDw, innerDh);
-                                mDimAnimator.updateParameters(mContext.getResources(),
-                                        w, currentTime);
-                            }
-                        }
-                        if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
-                            if (!blurring) {
-                                //Slog.i(TAG, "BLUR BEHIND: " + w);
-                                blurring = true;
-                                if (mBlurSurface == null) {
-                                    try {
-                                        mBlurSurface = new Surface(mFxSession, 0,
-                                                "BlurSurface",
-                                                -1, 16, 16,
-                                                PixelFormat.OPAQUE,
-                                                Surface.FX_SURFACE_BLUR);
-                                    } catch (Exception e) {
-                                        Slog.e(TAG, "Exception creating Blur surface", e);
-                                    }
-                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
-                                            + mBlurSurface + ": CREATE");
-                                }
-                                if (mBlurSurface != null) {
-                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
-                                            + mBlurSurface + ": pos=(0,0) (" +
-                                            dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
-                                    mBlurSurface.setPosition(0, 0);
-                                    mBlurSurface.setSize(dw, dh);
-                                    mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR);
-                                    if (!mBlurShown) {
-                                        try {
-                                            if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
-                                                    + mBlurSurface + ": SHOW");
-                                            mBlurSurface.show();
-                                        } catch (RuntimeException e) {
-                                            Slog.w(TAG, "Failure showing blur surface", e);
-                                        }
-                                        mBlurShown = true;
-                                    }
-                                }
-                            }
-                        }
-                    }
+                w.mObscured = mInnerFields.mObscured;
+                if (!mInnerFields.mObscured) {
+                    handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
                 }
 
                 if (obscuredChanged && mWallpaperTarget == w) {
@@ -8660,11 +8824,12 @@
             }
 
             if (mDimAnimator != null && mDimAnimator.mDimShown) {
-                animating |= mDimAnimator.updateSurface(dimming, currentTime,
-                        mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully());
+                mInnerFields.mAnimating |=
+                        mDimAnimator.updateSurface(mInnerFields.mDimming, currentTime,
+                            mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully());
             }
 
-            if (!blurring && mBlurShown) {
+            if (!mInnerFields.mBlurring && mBlurShown) {
                 if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR " + mBlurSurface
                         + ": HIDE");
                 try {
@@ -8698,8 +8863,8 @@
 
         if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
                 "With display frozen, orientationChangeComplete="
-                + orientationChangeComplete);
-        if (orientationChangeComplete) {
+                + mInnerFields.mOrientationChangeComplete);
+        if (mInnerFields.mOrientationChangeComplete) {
             if (mWindowsFreezingScreen) {
                 mWindowsFreezingScreen = false;
                 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
@@ -8791,7 +8956,7 @@
 
         boolean needRelayout = false;
 
-        if (!animating && mAppTransitionRunning) {
+        if (!mInnerFields.mAnimating && mAppTransitionRunning) {
             // We have finished the animation of an app transition.  To do
             // this, we have delayed a lot of operations like showing and
             // hiding apps, moving apps in Z-order, etc.  The app token list
@@ -8813,33 +8978,32 @@
             needRelayout = adjustWallpaperWindowsLocked() != 0;
         }
         if (needRelayout) {
-            requestAnimationLocked(0);
-        } else if (animating) {
-            final int refreshTimeUs = (int)(1000 / mDisplay.getRefreshRate());
-            requestAnimationLocked(currentTime + refreshTimeUs - SystemClock.uptimeMillis());
+            requestTraversalLocked();
+        } else if (mInnerFields.mAnimating) {
+            mChoreographer.scheduleAnimation();
         }
 
         // Finally update all input windows now that the window changes have stabilized.
         mInputMonitor.updateInputWindowsLw(true /*force*/);
 
-        setHoldScreenLocked(holdScreen != null);
+        setHoldScreenLocked(mInnerFields.mHoldScreen != null);
         if (!mDisplayFrozen) {
-            if (screenBrightness < 0 || screenBrightness > 1.0f) {
+            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
                 mPowerManager.setScreenBrightnessOverride(-1);
             } else {
                 mPowerManager.setScreenBrightnessOverride((int)
-                        (screenBrightness * Power.BRIGHTNESS_ON));
+                        (mInnerFields.mScreenBrightness * Power.BRIGHTNESS_ON));
             }
-            if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
+            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
                 mPowerManager.setButtonBrightnessOverride(-1);
             } else {
                 mPowerManager.setButtonBrightnessOverride((int)
-                        (buttonBrightness * Power.BRIGHTNESS_ON));
+                        (mInnerFields.mButtonBrightness * Power.BRIGHTNESS_ON));
             }
         }
-        if (holdScreen != mHoldingScreenOn) {
-            mHoldingScreenOn = holdScreen;
-            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
+        if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
+            mHoldingScreenOn = mInnerFields.mHoldScreen;
+            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen);
             mH.sendMessage(m);
         }
 
@@ -8849,23 +9013,17 @@
                     LocalPowerManager.BUTTON_EVENT, true);
             mTurnOnScreen = false;
         }
-        
-        if (screenRotationFinished && mScreenRotationAnimation != null) {
-            mScreenRotationAnimation.kill();
-            mScreenRotationAnimation = null;
-        }
 
         if (updateRotation) {
             if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
-            boolean changed = updateRotationUncheckedLocked(false);
-            if (changed) {
+            if (updateRotationUncheckedLocked(false)) {
                 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
             } else {
                 updateRotation = false;
             }
         }
 
-        if (orientationChangeComplete && !needRelayout && !updateRotation) {
+        if (mInnerFields.mOrientationChangeComplete && !needRelayout && !updateRotation) {
             checkDrawnWindowsLocked();
         }
 
@@ -8935,10 +9093,17 @@
         }
     }
 
-    void requestAnimationLocked(long delay) {
-        if (!mAnimationPending) {
-            mAnimationPending = true;
-            mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
+    void requestTraversalLocked() {
+        if (!mTraversalScheduled) {
+            mTraversalScheduled = true;
+            mH.sendEmptyMessage(H.DO_TRAVERSAL);
+        }
+    }
+
+    @Override
+    public void onAnimate() {
+        synchronized(mWindowMap) {
+            performLayoutAndPlaceSurfacesLocked();
         }
     }
 
@@ -9219,7 +9384,7 @@
         }
 
         if (CUSTOM_SCREEN_ROTATION) {
-            if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
+            if (mScreenRotationAnimation != null) {
                 mScreenRotationAnimation.kill();
                 mScreenRotationAnimation = null;
             }
@@ -9258,7 +9423,7 @@
             if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
             if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                     mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
-                requestAnimationLocked(0);
+                mChoreographer.scheduleAnimation();
             } else {
                 mScreenRotationAnimation = null;
                 updateRotation = true;
@@ -9750,10 +9915,15 @@
             pw.print("  mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
                     pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
             pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
-            pw.print("  mAnimationPending="); pw.print(mAnimationPending);
-                    pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
-                    pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
-            pw.print("  mNextAppTransition=0x");
+            if (mScreenRotationAnimation != null) {
+                pw.println("  mScreenRotationAnimation:");
+                mScreenRotationAnimation.printTo("    ", pw);
+            }
+            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
+                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
+                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
+            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
+                    pw.print("  mNextAppTransition=0x");
                     pw.print(Integer.toHexString(mNextAppTransition));
                     pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
             pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 9118381..6868cf6 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -238,6 +238,12 @@
     // we can give the window focus before waiting for the relayout.
     boolean mRelayoutCalled;
 
+    // If the application has called relayout() with changes that can
+    // impact its window's size, we need to perform a layout pass on it
+    // even if it is not currently visible for layout.  This is set
+    // when in that case until the layout is done.
+    boolean mLayoutNeeded;
+
     // This is set after the Surface has been created but before the
     // window has been drawn.  During this time the surface is hidden.
     boolean mDrawPending;
@@ -1449,7 +1455,7 @@
         return mViewVisibility == View.GONE
                 || !mRelayoutCalled
                 || (atoken == null && mRootToken.hidden)
-                || (atoken != null && atoken.hiddenRequested)
+                || (atoken != null && (atoken.hiddenRequested || atoken.hidden))
                 || mAttachedHidden
                 || mExiting || mDestroying;
     }
@@ -1587,7 +1593,7 @@
             mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
         }
         if (requestAnim) {
-            mService.requestAnimationLocked(0);
+            mService.mChoreographer.scheduleAnimation();
         }
         return true;
     }
@@ -1628,7 +1634,7 @@
             }
         }
         if (requestAnim) {
-            mService.requestAnimationLocked(0);
+            mService.mChoreographer.scheduleAnimation();
         }
         return true;
     }
@@ -1728,8 +1734,9 @@
                     pw.print(mPolicyVisibilityAfterAnim);
                     pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
         }
-        if (!mRelayoutCalled) {
-            pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled);
+        if (!mRelayoutCalled || mLayoutNeeded) {
+            pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
+                    pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded);
         }
         if (mSurfaceResized || mSurfaceDestroyDeferred) {
             pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized);
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 6fa5dfa..c63b84df 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -9,6 +9,7 @@
     com_android_server_InputWindowHandle.cpp \
     com_android_server_LightsService.cpp \
     com_android_server_PowerManagerService.cpp \
+    com_android_server_SerialService.cpp \
     com_android_server_SystemServer.cpp \
     com_android_server_UsbDeviceManager.cpp \
     com_android_server_UsbHostManager.cpp \
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 1cadc4e..ca6f206 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -233,75 +233,75 @@
     DIR* dir = opendir(POWER_SUPPLY_PATH);
     if (dir == NULL) {
         ALOGE("Could not open %s\n", POWER_SUPPLY_PATH);
-        return -1;
-    }
-    while ((entry = readdir(dir))) {
-        const char* name = entry->d_name;
+    } else {
+        while ((entry = readdir(dir))) {
+            const char* name = entry->d_name;
 
-        // ignore "." and ".."
-        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
-            continue;
-        }
-
-        char buf[20];
-        // Look for "type" file in each subdirectory
-        snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
-        int length = readFromFile(path, buf, sizeof(buf));
-        if (length > 0) {
-            if (buf[length - 1] == '\n')
-                buf[length - 1] = 0;
-
-            if (strcmp(buf, "Mains") == 0) {
-                snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.acOnlinePath = strdup(path);
+            // ignore "." and ".."
+            if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+                continue;
             }
-            else if (strcmp(buf, "USB") == 0) {
-                snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.usbOnlinePath = strdup(path);
-            }
-            else if (strcmp(buf, "Battery") == 0) {
-                snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryStatusPath = strdup(path);
-                snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryHealthPath = strdup(path);
-                snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryPresentPath = strdup(path);
-                snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryCapacityPath = strdup(path);
 
-                snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0) {
-                    gPaths.batteryVoltagePath = strdup(path);
-                    // voltage_now is in microvolts, not millivolts
-                    gVoltageDivisor = 1000;
-                } else {
-                    snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
+            char buf[20];
+            // Look for "type" file in each subdirectory
+            snprintf(path, sizeof(path), "%s/%s/type", POWER_SUPPLY_PATH, name);
+            int length = readFromFile(path, buf, sizeof(buf));
+            if (length > 0) {
+                if (buf[length - 1] == '\n')
+                    buf[length - 1] = 0;
+
+                if (strcmp(buf, "Mains") == 0) {
+                    snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
                     if (access(path, R_OK) == 0)
+                        gPaths.acOnlinePath = strdup(path);
+                }
+                else if (strcmp(buf, "USB") == 0) {
+                    snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        gPaths.usbOnlinePath = strdup(path);
+                }
+                else if (strcmp(buf, "Battery") == 0) {
+                    snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        gPaths.batteryStatusPath = strdup(path);
+                    snprintf(path, sizeof(path), "%s/%s/health", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        gPaths.batteryHealthPath = strdup(path);
+                    snprintf(path, sizeof(path), "%s/%s/present", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        gPaths.batteryPresentPath = strdup(path);
+                    snprintf(path, sizeof(path), "%s/%s/capacity", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        gPaths.batteryCapacityPath = strdup(path);
+
+                    snprintf(path, sizeof(path), "%s/%s/voltage_now", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0) {
                         gPaths.batteryVoltagePath = strdup(path);
-                }
+                        // voltage_now is in microvolts, not millivolts
+                        gVoltageDivisor = 1000;
+                    } else {
+                        snprintf(path, sizeof(path), "%s/%s/batt_vol", POWER_SUPPLY_PATH, name);
+                        if (access(path, R_OK) == 0)
+                            gPaths.batteryVoltagePath = strdup(path);
+                    }
 
-                snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0) {
-                    gPaths.batteryTemperaturePath = strdup(path);
-                } else {
-                    snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
-                    if (access(path, R_OK) == 0)
+                    snprintf(path, sizeof(path), "%s/%s/temp", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0) {
                         gPaths.batteryTemperaturePath = strdup(path);
-                }
+                    } else {
+                        snprintf(path, sizeof(path), "%s/%s/batt_temp", POWER_SUPPLY_PATH, name);
+                        if (access(path, R_OK) == 0)
+                            gPaths.batteryTemperaturePath = strdup(path);
+                    }
 
-                snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
-                if (access(path, R_OK) == 0)
-                    gPaths.batteryTechnologyPath = strdup(path);
+                    snprintf(path, sizeof(path), "%s/%s/technology", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        gPaths.batteryTechnologyPath = strdup(path);
+                }
             }
         }
+        closedir(dir);
     }
-    closedir(dir);
 
     if (!gPaths.acOnlinePath)
         ALOGE("acOnlinePath not found");
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index e163826..5c3e002 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -71,7 +71,6 @@
     jmethodID getExcludedDeviceNames;
     jmethodID getKeyRepeatTimeout;
     jmethodID getKeyRepeatDelay;
-    jmethodID getMaxEventsPerSecond;
     jmethodID getHoverTapTimeout;
     jmethodID getHoverTapSlop;
     jmethodID getDoubleTapTimeout;
@@ -586,12 +585,6 @@
     if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
         outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
     }
-
-    jint maxEventsPerSecond = env->CallIntMethod(mCallbacksObj,
-            gCallbacksClassInfo.getMaxEventsPerSecond);
-    if (!checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) {
-        outConfig->maxEventsPerSecond = maxEventsPerSecond;
-    }
 }
 
 bool NativeInputManager::isKeyRepeatEnabled() {
@@ -1480,9 +1473,6 @@
     GET_METHOD_ID(gCallbacksClassInfo.getLongPressTimeout, clazz,
             "getLongPressTimeout", "()I");
 
-    GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, clazz,
-            "getMaxEventsPerSecond", "()I");
-
     GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, clazz,
             "getPointerLayer", "()I");
 
diff --git a/services/jni/com_android_server_SerialService.cpp b/services/jni/com_android_server_SerialService.cpp
new file mode 100644
index 0000000..b889b78
--- /dev/null
+++ b/services/jni/com_android_server_SerialService.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SerialServiceJNI"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android
+{
+
+static struct parcel_file_descriptor_offsets_t
+{
+    jclass mClass;
+    jmethodID mConstructor;
+} gParcelFileDescriptorOffsets;
+
+static jobject android_server_SerialService_open(JNIEnv *env, jobject thiz, jstring path)
+{
+    const char *pathStr = env->GetStringUTFChars(path, NULL);
+
+    int fd = open(pathStr, O_RDWR | O_NOCTTY);
+    if (fd < 0) {
+        ALOGE("could not open %s", pathStr);
+        env->ReleaseStringUTFChars(path, pathStr);
+        return NULL;
+    }
+    env->ReleaseStringUTFChars(path, pathStr);
+
+    jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+    if (fileDescriptor == NULL) {
+        return NULL;
+    }
+    return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+        gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
+}
+
+
+static JNINativeMethod method_table[] = {
+    { "native_open",                "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
+                                    (void*)android_server_SerialService_open },
+};
+
+int register_android_server_SerialService(JNIEnv *env)
+{
+    jclass clazz = env->FindClass("com/android/server/SerialService");
+    if (clazz == NULL) {
+        ALOGE("Can't find com/android/server/SerialService");
+        return -1;
+    }
+
+    clazz = env->FindClass("android/os/ParcelFileDescriptor");
+    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
+    gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+    gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
+    LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
+                 "Unable to find constructor for android.os.ParcelFileDescriptor");
+
+    return jniRegisterNativeMethods(env, "com/android/server/SerialService",
+            method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index c7beb5f..423ebd1 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -27,6 +27,7 @@
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
 int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_SerialService(JNIEnv* env);
 int register_android_server_UsbDeviceManager(JNIEnv* env);
 int register_android_server_UsbHostManager(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
@@ -49,6 +50,7 @@
     ALOG_ASSERT(env, "Could not retrieve the env!");
 
     register_android_server_PowerManagerService(env);
+    register_android_server_SerialService(env);
     register_android_server_InputApplicationHandle(env);
     register_android_server_InputWindowHandle(env);
     register_android_server_InputManager(env);
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 95d651a..42e280f 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -23,18 +23,21 @@
 LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
 
+ifeq ($(TARGET_HAS_WAITFORVSYNC), true)
+	LOCAL_CFLAGS += -DHAS_WAITFORVSYNC
+endif
+
 ifeq ($(TARGET_BOARD_PLATFORM), omap3)
 	LOCAL_CFLAGS += -DNO_RGBX_8888
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), omap4)
 	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
+	LOCAL_CFLAGS += -DUSE_TRIPLE_BUFFERING
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
 	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
-	LOCAL_CFLAGS += -DREFRESH_RATE=56
 endif
 
-
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libhardware \
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 438a6da..986aec5 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -350,15 +350,28 @@
 }
 
 // this needs to be thread safe
-nsecs_t DisplayHardware::waitForVSync() const {
+nsecs_t DisplayHardware::waitForRefresh() const {
     nsecs_t timestamp;
     if (mVSync.wait(&timestamp) < 0) {
         // vsync not supported!
         usleep( getDelayToNextVSyncUs(&timestamp) );
     }
+    mLastHwVSync = timestamp; // FIXME: Not thread safe
     return timestamp;
 }
 
+nsecs_t DisplayHardware::getRefreshTimestamp() const {
+    // this returns the last refresh timestamp.
+    // if the last one is not available, we estimate it based on
+    // the refresh period and whatever closest timestamp we have.
+    nsecs_t now = systemTime();
+    return now - ((now - mLastHwVSync) %  mRefreshPeriod);
+}
+
+nsecs_t DisplayHardware::getRefreshPeriod() const {
+    return mRefreshPeriod;
+}
+
 int32_t DisplayHardware::getDelayToNextVSyncUs(nsecs_t* timestamp) const {
     Mutex::Autolock _l(mFakeVSyncMutex);
     const nsecs_t period = mRefreshPeriod;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 77da272..02be4dc 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -76,7 +76,9 @@
     uint32_t    getMaxViewportDims() const;
 
     // waits for the next vsync and returns the timestamp of when it happened
-    nsecs_t        waitForVSync() const;
+    nsecs_t     waitForRefresh() const;
+    nsecs_t     getRefreshPeriod() const;
+    nsecs_t     getRefreshTimestamp() const;
 
     uint32_t getPageFlipCount() const;
     EGLDisplay getEGLDisplay() const { return mDisplay; }
@@ -119,6 +121,7 @@
     mutable Mutex   mFakeVSyncMutex;
     mutable nsecs_t mNextFakeVSync;
     nsecs_t         mRefreshPeriod;
+    mutable nsecs_t mLastHwVSync;
 
     HWComposer*     mHwc;
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index f4afeea..69f1aca 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -22,15 +21,6 @@
 
 #include <unistd.h>
 #include <fcntl.h>
-#include <signal.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/resource.h>
-
-#include <linux/unistd.h>
 
 #include <utils/Log.h>
 
@@ -45,39 +35,22 @@
 
 // ----------------------------------------------------------------------------
 
-DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase(
+DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
         const sp<SurfaceFlinger>& flinger)
     : Thread(false), mFlinger(flinger) {
 }
 
-DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() {
+DisplayHardwareBase::DisplayEventThread::~DisplayEventThread() {
 }
 
-// ----------------------------------------------------------------------------
-
-DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
-        const sp<SurfaceFlinger>& flinger)
-    : DisplayEventThreadBase(flinger)
-{
+status_t DisplayHardwareBase::DisplayEventThread::initCheck() const {
+    return ((access(kSleepFileName, R_OK) == 0 &&
+            access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;
 }
 
-DisplayHardwareBase::DisplayEventThread::~DisplayEventThread()
-{
-}
+bool DisplayHardwareBase::DisplayEventThread::threadLoop() {
 
-bool DisplayHardwareBase::DisplayEventThread::threadLoop()
-{
-    int err = 0;
-    char buf;
-    int fd;
-
-    fd = open(kSleepFileName, O_RDONLY, 0);
-    do {
-      err = read(fd, &buf, 1);
-    } while (err < 0 && errno == EINTR);
-    close(fd);
-    ALOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
-    if (err >= 0) {
+    if (waitForFbSleep() == NO_ERROR) {
         sp<SurfaceFlinger> flinger = mFlinger.promote();
         ALOGD("About to give-up screen, flinger = %p", flinger.get());
         if (flinger != 0) {
@@ -85,39 +58,51 @@
             flinger->screenReleased(0);
             mBarrier.wait();
         }
+        if (waitForFbWake() == NO_ERROR) {
+            sp<SurfaceFlinger> flinger = mFlinger.promote();
+            ALOGD("Screen about to return, flinger = %p", flinger.get());
+            if (flinger != 0) {
+                flinger->screenAcquired(0);
+            }
+            return true;
+        }
     }
-    fd = open(kWakeFileName, O_RDONLY, 0);
+
+    // error, exit the thread
+    return false;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::waitForFbSleep() {
+    int err = 0;
+    char buf;
+    int fd = open(kSleepFileName, O_RDONLY, 0);
+    // if the file doesn't exist, the error will be caught in read() below
     do {
-      err = read(fd, &buf, 1);
+        err = read(fd, &buf, 1);
     } while (err < 0 && errno == EINTR);
     close(fd);
-    ALOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
-    if (err >= 0) {
-        sp<SurfaceFlinger> flinger = mFlinger.promote();
-        ALOGD("Screen about to return, flinger = %p", flinger.get());
-        if (flinger != 0)
-            flinger->screenAcquired(0);
-    }
-    return true;
+    ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
+    return err < 0 ? -errno : int(NO_ERROR);
 }
 
-status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const
-{
+status_t DisplayHardwareBase::DisplayEventThread::waitForFbWake() {
+    int err = 0;
+    char buf;
+    int fd = open(kWakeFileName, O_RDONLY, 0);
+    // if the file doesn't exist, the error will be caught in read() below
+    do {
+        err = read(fd, &buf, 1);
+    } while (err < 0 && errno == EINTR);
+    close(fd);
+    ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
+    return err < 0 ? -errno : int(NO_ERROR);
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const {
     mBarrier.open();
     return NO_ERROR;
 }
 
-status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
-{
-    return NO_ERROR;
-}
-
-status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
-{
-    return ((access(kSleepFileName, R_OK) == 0 &&
-            access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;
-}
-
 // ----------------------------------------------------------------------------
 
 DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
@@ -127,35 +112,35 @@
     mDisplayEventThread = new DisplayEventThread(flinger);
 }
 
-DisplayHardwareBase::~DisplayHardwareBase()
-{
+void DisplayHardwareBase::startSleepManagement() const {
+    if (mDisplayEventThread->initCheck() == NO_ERROR) {
+        mDisplayEventThread->run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
+    } else {
+        ALOGW("/sys/power/wait_for_fb_{wake|sleep} don't exist");
+    }
+}
+
+DisplayHardwareBase::~DisplayHardwareBase() {
     // request exit
     mDisplayEventThread->requestExitAndWait();
 }
 
-bool DisplayHardwareBase::canDraw() const
-{
+bool DisplayHardwareBase::canDraw() const {
     return mScreenAcquired;
 }
 
-void DisplayHardwareBase::releaseScreen() const
-{
+void DisplayHardwareBase::releaseScreen() const {
     status_t err = mDisplayEventThread->releaseScreen();
     if (err >= 0) {
         mScreenAcquired = false;
     }
 }
 
-void DisplayHardwareBase::acquireScreen() const
-{
-    status_t err = mDisplayEventThread->acquireScreen();
-    if (err >= 0) {
-        mScreenAcquired = true;
-    }
+void DisplayHardwareBase::acquireScreen() const {
+    mScreenAcquired = true;
 }
 
-bool DisplayHardwareBase::isScreenAcquired() const
-{
+bool DisplayHardwareBase::isScreenAcquired() const {
     return mScreenAcquired;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index ef2df43..fba211b 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2012 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.
@@ -20,8 +20,6 @@
 #include <stdint.h>
 #include <utils/RefBase.h>
 #include <utils/threads.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
 #include "Barrier.h"
 
 namespace android {
@@ -31,11 +29,13 @@
 class DisplayHardwareBase
 {
 public:
-                DisplayHardwareBase(
-                        const sp<SurfaceFlinger>& flinger,
-                        uint32_t displayIndex);
+    DisplayHardwareBase(
+            const sp<SurfaceFlinger>& flinger,
+            uint32_t displayIndex);
 
-                ~DisplayHardwareBase();
+    ~DisplayHardwareBase();
+
+    void startSleepManagement() const;
 
     // console management
     void releaseScreen() const;
@@ -46,34 +46,21 @@
 
 
 private:
-    class DisplayEventThreadBase : public Thread {
-    protected:
+    class DisplayEventThread : public Thread {
         wp<SurfaceFlinger> mFlinger;
-    public:
-        DisplayEventThreadBase(const sp<SurfaceFlinger>& flinger);
-        virtual ~DisplayEventThreadBase();
-        virtual void onFirstRef() {
-            run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
-        }
-        virtual status_t acquireScreen() const { return NO_ERROR; };
-        virtual status_t releaseScreen() const { return NO_ERROR; };
-        virtual status_t initCheck() const = 0;
-    };
-
-    class DisplayEventThread : public DisplayEventThreadBase 
-    {
         mutable Barrier mBarrier;
+        status_t waitForFbSleep();
+        status_t waitForFbWake();
     public:
-                DisplayEventThread(const sp<SurfaceFlinger>& flinger);
+        DisplayEventThread(const sp<SurfaceFlinger>& flinger);
         virtual ~DisplayEventThread();
         virtual bool threadLoop();
-        virtual status_t readyToRun();
-        virtual status_t releaseScreen() const;
-        virtual status_t initCheck() const;
+        status_t releaseScreen() const;
+        status_t initCheck() const;
     };
 
-    sp<DisplayEventThreadBase>  mDisplayEventThread;
-    mutable int                 mScreenAcquired;
+    sp<DisplayEventThread>  mDisplayEventThread;
+    mutable int             mScreenAcquired;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 80ab519..af0da0b 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -36,6 +36,7 @@
 EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
     : mFlinger(flinger),
       mHw(flinger->graphicPlane(0).displayHardware()),
+      mLastVSyncTimestamp(0),
       mDeliveredEvents(0)
 {
 }
@@ -44,6 +45,20 @@
     run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
 }
 
+sp<DisplayEventConnection> EventThread::createEventConnection() const {
+    return new DisplayEventConnection(const_cast<EventThread*>(this));
+}
+
+nsecs_t EventThread::getLastVSyncTimestamp() const {
+    Mutex::Autolock _l(mLock);
+    return mLastVSyncTimestamp;
+}
+
+nsecs_t EventThread::getVSyncPeriod() const {
+    return mHw.getRefreshPeriod();
+
+}
+
 status_t EventThread::registerDisplayEventConnection(
         const sp<DisplayEventConnection>& connection) {
     Mutex::Autolock _l(mLock);
@@ -80,8 +95,11 @@
         Mutex::Autolock _l(mLock);
         ConnectionInfo* info = getConnectionInfoLocked(connection);
         if (info) {
-            info->count = (count == 0) ? -1 : count;
-            mCondition.signal();
+            const int32_t new_count = (count == 0) ? -1 : count;
+            if (info->count != new_count) {
+                info->count = new_count;
+                mCondition.signal();
+            }
         }
     }
 }
@@ -90,10 +108,8 @@
         const wp<DisplayEventConnection>& connection) {
     Mutex::Autolock _l(mLock);
     ConnectionInfo* info = getConnectionInfoLocked(connection);
-    if (info) {
-        if (info->count < 0) {
-            info->count = 0;
-        }
+    if (info && info->count < 0) {
+        info->count = 0;
         mCondition.signal();
     }
 }
@@ -129,14 +145,15 @@
 
             // at least one listener requested VSYNC
             mLock.unlock();
-            timestamp = mHw.waitForVSync();
+            timestamp = mHw.waitForRefresh();
             mLock.lock();
             mDeliveredEvents++;
+            mLastVSyncTimestamp = timestamp;
 
             // now see if we still need to report this VSYNC event
-            bool reportVsync = false;
-            size_t count = mDisplayEventConnections.size();
+            const size_t count = mDisplayEventConnections.size();
             for (size_t i=0 ; i<count ; i++) {
+                bool reportVsync = false;
                 const ConnectionInfo& info(
                         mDisplayEventConnections.valueAt(i));
                 if (info.count >= 1) {
@@ -157,11 +174,7 @@
                     displayEventConnections.add(mDisplayEventConnections.keyAt(i));
                 }
             }
-
-            if (reportVsync) {
-                break;
-            }
-        } while (true);
+        } while (!displayEventConnections.size());
 
         // dispatch vsync events to listeners...
         vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 35bd299..3a3071e 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -36,6 +36,7 @@
 
 class SurfaceFlinger;
 class DisplayHardware;
+class DisplayEventConnection;
 
 // ---------------------------------------------------------------------------
 
@@ -45,6 +46,8 @@
 public:
     EventThread(const sp<SurfaceFlinger>& flinger);
 
+    sp<DisplayEventConnection> createEventConnection() const;
+
     status_t registerDisplayEventConnection(
             const sp<DisplayEventConnection>& connection);
 
@@ -56,6 +59,10 @@
 
     void requestNextVsync(const wp<DisplayEventConnection>& connection);
 
+    nsecs_t getLastVSyncTimestamp() const;
+
+    nsecs_t getVSyncPeriod() const;
+
     void dump(String8& result, char* buffer, size_t SIZE) const;
 
 private:
@@ -88,6 +95,7 @@
 
     // protected by mLock
     KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections;
+    nsecs_t mLastVSyncTimestamp;
 
     // main thread only
     size_t mDeliveredEvents;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d4c4b1f..3e6b872 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -38,6 +38,7 @@
 #include "Layer.h"
 #include "SurfaceFlinger.h"
 #include "SurfaceTextureLayer.h"
+#include <math.h>
 
 #define DEBUG_RESIZE    0
 
@@ -54,6 +55,9 @@
         mCurrentTransform(0),
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mCurrentOpacity(true),
+        mRefreshPending(0),
+        mFrameLatencyNeeded(false),
+        mFrameLatencyOffset(0),
         mFormat(PIXEL_FORMAT_NONE),
         mGLExtensions(GLExtensions::getInstance()),
         mOpaqueLayer(true),
@@ -65,6 +69,17 @@
     glGenTextures(1, &mTextureName);
 }
 
+void Layer::onLayerDisplayed() {
+    if (mFrameLatencyNeeded) {
+        const DisplayHardware& hw(graphicPlane(0).displayHardware());
+        mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp();
+        mFrameStats[mFrameLatencyOffset].set = systemTime();
+        mFrameStats[mFrameLatencyOffset].vsync = hw.getRefreshTimestamp();
+        mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128;
+        mFrameLatencyNeeded = false;
+    }
+}
+
 void Layer::onFirstRef()
 {
     LayerBaseClient::onFirstRef();
@@ -83,7 +98,12 @@
     mSurfaceTexture = new SurfaceTextureLayer(mTextureName, this);
     mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
     mSurfaceTexture->setSynchronousMode(true);
+#ifdef USE_TRIPLE_BUFFERING
+#warning "using triple buffering"
+    mSurfaceTexture->setBufferCountServer(3);
+#else
     mSurfaceTexture->setBufferCountServer(2);
+#endif
 }
 
 Layer::~Layer()
@@ -94,7 +114,7 @@
 
 void Layer::onFrameQueued() {
     android_atomic_inc(&mQueuedFrames);
-    mFlinger->signalEvent();
+    mFlinger->signalLayerUpdate();
 }
 
 // called with SurfaceFlinger::mStateLock as soon as the layer is entered
@@ -388,16 +408,37 @@
 // pageflip handling...
 // ----------------------------------------------------------------------------
 
+bool Layer::onPreComposition()
+{
+    // if there was more than one pending update, request a refresh
+    if (mRefreshPending >= 2) {
+        mRefreshPending = 0;
+        return true;
+    }
+    mRefreshPending = 0;
+    return false;
+}
+
 void Layer::lockPageFlip(bool& recomputeVisibleRegions)
 {
     if (mQueuedFrames > 0) {
+
+        // if we've already called updateTexImage() without going through
+        // a composition step, we have to skip this layer at this point
+        // because we cannot call updateTeximage() without a corresponding
+        // compositionComplete() call.
+        // we'll trigger an update in onPreComposition().
+        if (mRefreshPending++) {
+            return;
+        }
+
         // Capture the old state of the layer for comparisons later
         const bool oldOpacity = isOpaque();
         sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
 
         // signal another event if we have more frames pending
         if (android_atomic_dec(&mQueuedFrames) > 1) {
-            mFlinger->signalEvent();
+            mFlinger->signalLayerUpdate();
         }
 
         if (mSurfaceTexture->updateTexImage() < NO_ERROR) {
@@ -408,6 +449,7 @@
 
         // update the active buffer
         mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
+        mFrameLatencyNeeded = true;
 
         const Rect crop(mSurfaceTexture->getCurrentCrop());
         const uint32_t transform(mSurfaceTexture->getCurrentTransform());
@@ -499,6 +541,10 @@
 void Layer::unlockPageFlip(
         const Transform& planeTransform, Region& outDirtyRegion)
 {
+    if (mRefreshPending >= 2) {
+        return;
+    }
+
     Region dirtyRegion(mPostedDirtyRegion);
     if (!dirtyRegion.isEmpty()) {
         mPostedDirtyRegion.clear();
@@ -532,9 +578,9 @@
     snprintf(buffer, SIZE,
             "      "
             "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
-            " transform-hint=0x%02x, queued-frames=%d\n",
+            " transform-hint=0x%02x, queued-frames=%d, mRefreshPending=%d\n",
             mFormat, w0, h0, s0,f0,
-            getTransformHint(), mQueuedFrames);
+            getTransformHint(), mQueuedFrames, mRefreshPending);
 
     result.append(buffer);
 
@@ -543,6 +589,32 @@
     }
 }
 
+void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const
+{
+    LayerBaseClient::dumpStats(result, buffer, SIZE);
+    const size_t o = mFrameLatencyOffset;
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const nsecs_t period = hw.getRefreshPeriod();
+    result.appendFormat("%lld\n", period);
+    for (size_t i=0 ; i<128 ; i++) {
+        const size_t index = (o+i) % 128;
+        const nsecs_t time_app   = mFrameStats[index].timestamp;
+        const nsecs_t time_set   = mFrameStats[index].set;
+        const nsecs_t time_vsync = mFrameStats[index].vsync;
+        result.appendFormat("%lld\t%lld\t%lld\n",
+                time_app,
+                time_vsync,
+                time_set);
+    }
+    result.append("\n");
+}
+
+void Layer::clearStats()
+{
+    LayerBaseClient::clearStats();
+    memset(mFrameStats, 0, sizeof(mFrameStats));
+}
+
 uint32_t Layer::getEffectiveUsage(uint32_t usage) const
 {
     // TODO: should we do something special if mSecure is set?
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2b9471b..bf30608 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -34,6 +34,7 @@
 #include "LayerBase.h"
 #include "SurfaceTextureLayer.h"
 #include "Transform.h"
+#include <utils/Timers.h>
 
 namespace android {
 
@@ -78,12 +79,17 @@
     // LayerBaseClient interface
     virtual wp<IBinder> getSurfaceTextureBinder() const;
 
+    virtual void onLayerDisplayed();
+    virtual bool onPreComposition();
+
     // only for debugging
     inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
 
 protected:
     virtual void onFirstRef();
     virtual void dump(String8& result, char* scratch, size_t size) const;
+    virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
+    virtual void clearStats();
 
 private:
     friend class SurfaceTextureLayer;
@@ -110,6 +116,19 @@
     uint32_t mCurrentTransform;
     uint32_t mCurrentScalingMode;
     bool mCurrentOpacity;
+    size_t mRefreshPending;
+    bool mFrameLatencyNeeded;
+    int mFrameLatencyOffset;
+
+    struct Statistics {
+        Statistics() : timestamp(0), set(0), vsync(0) { }
+        nsecs_t timestamp;  // buffer timestamp
+        nsecs_t set;        // buffer displayed timestamp
+        nsecs_t vsync;      // vsync immediately before set
+    };
+
+    // protected by mLock
+    Statistics mFrameStats[128];
 
     // constants
     PixelFormat mFormat;
@@ -121,9 +140,6 @@
     bool mSecure;         // no screenshots
     bool mProtectedByApp; // application requires protected path to external sink
     Region mPostedDirtyRegion;
-
-    // binder thread, transaction thread
-    mutable Mutex mLock;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 37879f1..e764001 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -47,8 +47,7 @@
       mOrientation(0),
       mPlaneOrientation(0),
       mTransactionFlags(0),
-      mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
-      mInvalidate(0)
+      mPremultipliedAlpha(true), mName("unnamed"), mDebug(false)
 {
     const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
     mFlags = hw.getFlags();
@@ -262,23 +261,11 @@
     mTransformedBounds = tr.makeBounds(w, h);
 }
 
-void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
-{
+void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) {
 }
 
 void LayerBase::unlockPageFlip(
-        const Transform& planeTransform, Region& outDirtyRegion)
-{
-    if ((android_atomic_and(~1, &mInvalidate)&1) == 1) {
-        outDirtyRegion.orSelf(visibleRegionScreen);
-    }
-}
-
-void LayerBase::invalidate()
-{
-    if ((android_atomic_or(1, &mInvalidate)&1) == 0) {
-        mFlinger->signalEvent();
-    }
+        const Transform& planeTransform, Region& outDirtyRegion) {
 }
 
 void LayerBase::drawRegion(const Region& reg) const
@@ -471,13 +458,21 @@
 void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
 {
     const Layer::State& s(drawingState());
+
     snprintf(buffer, SIZE,
-            "+ %s %p (%s)\n"
+            "+ %s %p (%s)\n",
+            getTypeId(), this, getName().string());
+    result.append(buffer);
+
+    s.transparentRegion.dump(result, "transparentRegion");
+    transparentRegionScreen.dump(result, "transparentRegionScreen");
+    visibleRegionScreen.dump(result, "visibleRegionScreen");
+
+    snprintf(buffer, SIZE,
             "      "
             "z=%9d, pos=(%g,%g), size=(%4d,%4d), "
             "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
-            getTypeId(), this, getName().string(),
             s.z, s.transform.tx(), s.transform.ty(), s.w, s.h,
             isOpaque(), needsDithering(), contentDirty,
             s.alpha, s.flags,
@@ -486,11 +481,15 @@
     result.append(buffer);
 }
 
-void LayerBase::shortDump(String8& result, char* scratch, size_t size) const
-{
+void LayerBase::shortDump(String8& result, char* scratch, size_t size) const {
     LayerBase::dump(result, scratch, size);
 }
 
+void LayerBase::dumpStats(String8& result, char* scratch, size_t SIZE) const {
+}
+
+void LayerBase::clearStats() {
+}
 
 // ---------------------------------------------------------------------------
 
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 7f62145..b8f7680 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -103,8 +103,6 @@
             Rect visibleBounds() const;
             void drawRegion(const Region& reg) const;
 
-            void invalidate();
-
     virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; }
     virtual sp<Layer> getLayer() const { return 0; }
 
@@ -204,11 +202,22 @@
 
     /** called with the state lock when the surface is removed from the
      *  current list */
-    virtual void onRemoved() { };
-    
+    virtual void onRemoved() { }
+
+    /** called after page-flip
+     */
+    virtual void onLayerDisplayed() { }
+
+    /** called before composition.
+     * returns true if the layer has pending updates.
+     */
+    virtual bool onPreComposition() { return false; }
+
     /** always call base class first */
     virtual void dump(String8& result, char* scratch, size_t size) const;
     virtual void shortDump(String8& result, char* scratch, size_t size) const;
+    virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
+    virtual void clearStats();
 
 
     enum { // flags for doTransaction()
@@ -271,10 +280,6 @@
     mutable     bool            mDebug;
 
 
-                // atomic
-    volatile    int32_t         mInvalidate;
-                
-
 public:
     // called from class SurfaceFlinger
     virtual ~LayerBase();
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index cbd530c..290fff4 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -18,12 +18,18 @@
 #include <errno.h>
 #include <sys/types.h>
 
+#include <binder/IPCThreadState.h>
+
 #include <utils/threads.h>
 #include <utils/Timers.h>
 #include <utils/Log.h>
-#include <binder/IPCThreadState.h>
+
+#include <gui/IDisplayEventConnection.h>
+#include <gui/BitTube.h>
 
 #include "MessageQueue.h"
+#include "EventThread.h"
+#include "SurfaceFlinger.h"
 
 namespace android {
 
@@ -43,36 +49,69 @@
 
 // ---------------------------------------------------------------------------
 
+void MessageQueue::Handler::signalRefresh() {
+    if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
+        mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
+    }
+}
+
+void MessageQueue::Handler::signalInvalidate() {
+    if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
+        mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
+    }
+}
+
+void MessageQueue::Handler::handleMessage(const Message& message) {
+    switch (message.what) {
+        case INVALIDATE:
+            android_atomic_and(~eventMaskInvalidate, &mEventMask);
+            mQueue.mFlinger->onMessageReceived(message.what);
+            break;
+        case REFRESH:
+            android_atomic_and(~eventMaskRefresh, &mEventMask);
+            mQueue.mFlinger->onMessageReceived(message.what);
+            break;
+    }
+}
+
+// ---------------------------------------------------------------------------
+
 MessageQueue::MessageQueue()
-    : mLooper(new Looper(true)), mWorkPending(0)
 {
 }
 
 MessageQueue::~MessageQueue() {
 }
 
+void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
+{
+    mFlinger = flinger;
+    mLooper = new Looper(true);
+    mHandler = new Handler(*this);
+}
+
+void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
+{
+    mEventThread = eventThread;
+    mEvents = eventThread->createEventConnection();
+    mEventTube = mEvents->getDataChannel();
+    mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,
+            MessageQueue::cb_eventReceiver, this);
+}
+
 void MessageQueue::waitMessage() {
     do {
         IPCThreadState::self()->flushCommands();
-
         int32_t ret = mLooper->pollOnce(-1);
         switch (ret) {
             case ALOOPER_POLL_WAKE:
             case ALOOPER_POLL_CALLBACK:
-                // callback and/or wake
-                if (android_atomic_and(0, &mWorkPending)) {
-                    return;
-                }
                 continue;
-
+            case ALOOPER_POLL_ERROR:
+                ALOGE("ALOOPER_POLL_ERROR");
             case ALOOPER_POLL_TIMEOUT:
                 // timeout (should not happen)
                 continue;
-
-            case ALOOPER_POLL_ERROR:
-                ALOGE("ALOOPER_POLL_ERROR");
-                continue;
-
             default:
                 // should not happen
                 ALOGE("Looper::pollOnce() returned unknown status %d", ret);
@@ -93,11 +132,32 @@
     return NO_ERROR;
 }
 
-status_t MessageQueue::invalidate() {
-    if (android_atomic_or(1, &mWorkPending) == 0) {
-        mLooper->wake();
+void MessageQueue::invalidate() {
+//    mHandler->signalInvalidate();
+    mEvents->requestNextVsync();
+}
+
+void MessageQueue::refresh() {
+    mEvents->requestNextVsync();
+}
+
+int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
+    MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
+    return queue->eventReceiver(fd, events);
+}
+
+int MessageQueue::eventReceiver(int fd, int events) {
+    ssize_t n;
+    DisplayEventReceiver::Event buffer[8];
+    while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
+        for (int i=0 ; i<n ; i++) {
+            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+                mHandler->signalRefresh();
+                break;
+            }
+        }
     }
-    return NO_ERROR;
+    return 1;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 2317d81..ea29e7e 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -25,10 +25,16 @@
 #include <utils/Timers.h>
 #include <utils/Looper.h>
 
+#include <gui/DisplayEventReceiver.h>
+
 #include "Barrier.h"
 
 namespace android {
 
+class IDisplayEventConnection;
+class EventThread;
+class SurfaceFlinger;
+
 // ---------------------------------------------------------------------------
 
 class MessageBase : public MessageHandler
@@ -54,16 +60,48 @@
 // ---------------------------------------------------------------------------
 
 class MessageQueue {
+    class Handler : public MessageHandler {
+        enum {
+            eventMaskInvalidate = 0x1,
+            eventMaskRefresh    = 0x2
+        };
+        MessageQueue& mQueue;
+        int32_t mEventMask;
+    public:
+        Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
+        virtual void handleMessage(const Message& message);
+        void signalRefresh();
+        void signalInvalidate();
+    };
+
+    friend class Handler;
+
+    sp<SurfaceFlinger> mFlinger;
     sp<Looper> mLooper;
-    volatile int32_t mWorkPending;
+    sp<EventThread> mEventThread;
+    sp<IDisplayEventConnection> mEvents;
+    sp<BitTube> mEventTube;
+    sp<Handler> mHandler;
+
+
+    static int cb_eventReceiver(int fd, int events, void* data);
+    int eventReceiver(int fd, int events);
 
 public:
+    enum {
+        INVALIDATE = 0,
+        REFRESH    = 1,
+    };
+
     MessageQueue();
     ~MessageQueue();
+    void init(const sp<SurfaceFlinger>& flinger);
+    void setEventThread(const sp<EventThread>& events);
 
     void waitMessage();
     status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
-    status_t invalidate();
+    void invalidate();
+    void refresh();
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index af47402..40717f4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -125,11 +125,34 @@
     ALOGI_IF(mDebugDDMS,         "DDMS debugging enabled");
 }
 
+void SurfaceFlinger::onFirstRef()
+{
+    mEventQueue.init(this);
+
+    run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
+
+    // Wait for the main thread to be done with its initialization
+    mReadyToRunBarrier.wait();
+}
+
+
 SurfaceFlinger::~SurfaceFlinger()
 {
     glDeleteTextures(1, &mWormholeTexName);
 }
 
+void SurfaceFlinger::binderDied(const wp<IBinder>& who)
+{
+    // the window manager died on us. prepare its eulogy.
+
+    // reset screen orientation
+    Vector<ComposerState> state;
+    setTransactionState(state, eOrientationDefault, 0);
+
+    // restart the boot-animation
+    property_set("ctl.start", "bootanim");
+}
+
 sp<IMemoryHeap> SurfaceFlinger::getCblk() const
 {
     return mServerHeap;
@@ -183,25 +206,6 @@
     property_set("ctl.stop", "bootanim");
 }
 
-void SurfaceFlinger::binderDied(const wp<IBinder>& who)
-{
-    // the window manager died on us. prepare its eulogy.
-
-    // reset screen orientation
-    setOrientation(0, eOrientationDefault, 0);
-
-    // restart the boot-animation
-    property_set("ctl.start", "bootanim");
-}
-
-void SurfaceFlinger::onFirstRef()
-{
-    run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
-
-    // Wait for the main thread to be done with its initialization
-    mReadyToRunBarrier.wait();
-}
-
 static inline uint16_t pack565(int r, int g, int b) {
     return (r<<11)|(g<<5)|b;
 }
@@ -295,6 +299,8 @@
 
     // start the EventThread
     mEventThread = new EventThread(this);
+    mEventQueue.setEventThread(mEventThread);
+    hw.startSleepManagement();
 
     /*
      *  We're now ready to accept clients...
@@ -309,34 +315,6 @@
 }
 
 // ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Events Handler
-#endif
-
-void SurfaceFlinger::waitForEvent() {
-    mEventQueue.waitMessage();
-}
-
-void SurfaceFlinger::signalEvent() {
-    mEventQueue.invalidate();
-}
-
-status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
-        nsecs_t reltime, uint32_t flags) {
-    return mEventQueue.postMessage(msg, reltime);
-}
-
-status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
-        nsecs_t reltime, uint32_t flags) {
-    status_t res = mEventQueue.postMessage(msg, reltime);
-    if (res == NO_ERROR) {
-        msg->wait();
-    }
-    return res;
-}
-
-// ----------------------------------------------------------------------------
 
 bool SurfaceFlinger::authenticateSurfaceTexture(
         const sp<ISurfaceTexture>& surfaceTexture) const {
@@ -382,69 +360,118 @@
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
-    sp<DisplayEventConnection> result(new DisplayEventConnection(mEventThread));
-    return result;
+    return mEventThread->createEventConnection();
 }
 
 // ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Main loop
-#endif
+
+void SurfaceFlinger::waitForEvent() {
+    mEventQueue.waitMessage();
+}
+
+void SurfaceFlinger::signalTransaction() {
+    mEventQueue.invalidate();
+}
+
+void SurfaceFlinger::signalLayerUpdate() {
+    mEventQueue.invalidate();
+}
+
+void SurfaceFlinger::signalRefresh() {
+    mEventQueue.refresh();
+}
+
+status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
+        nsecs_t reltime, uint32_t flags) {
+    return mEventQueue.postMessage(msg, reltime);
+}
+
+status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
+        nsecs_t reltime, uint32_t flags) {
+    status_t res = mEventQueue.postMessage(msg, reltime);
+    if (res == NO_ERROR) {
+        msg->wait();
+    }
+    return res;
+}
 
 bool SurfaceFlinger::threadLoop()
 {
     waitForEvent();
-
-    // check for transactions
-    if (CC_UNLIKELY(mConsoleSignals)) {
-        handleConsoleEvents();
-    }
-
-    // if we're in a global transaction, don't do anything.
-    const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
-    uint32_t transactionFlags = peekTransactionFlags(mask);
-    if (CC_UNLIKELY(transactionFlags)) {
-        handleTransaction(transactionFlags);
-    }
-
-    // post surfaces (if needed)
-    handlePageFlip();
-
-    if (mDirtyRegion.isEmpty()) {
-        // nothing new to do.
-        return true;
-    }
-
-    if (CC_UNLIKELY(mHwWorkListDirty)) {
-        // build the h/w work list
-        handleWorkList();
-    }
-
-    const DisplayHardware& hw(graphicPlane(0).displayHardware());
-    if (CC_LIKELY(hw.canDraw())) {
-        // repaint the framebuffer (if needed)
-        handleRepaint();
-        // inform the h/w that we're done compositing
-        hw.compositionComplete();
-        postFramebuffer();
-    } else {
-        // pretend we did the post
-        hw.compositionComplete();
-        hw.waitForVSync();
-    }
     return true;
 }
 
+void SurfaceFlinger::onMessageReceived(int32_t what)
+{
+    switch (what) {
+        case MessageQueue::REFRESH: {
+//        case MessageQueue::INVALIDATE: {
+            // check for transactions
+            if (CC_UNLIKELY(mConsoleSignals)) {
+                handleConsoleEvents();
+            }
+
+            // if we're in a global transaction, don't do anything.
+            const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+            uint32_t transactionFlags = peekTransactionFlags(mask);
+            if (CC_UNLIKELY(transactionFlags)) {
+                handleTransaction(transactionFlags);
+            }
+
+            // post surfaces (if needed)
+            handlePageFlip();
+
+//            signalRefresh();
+//
+//        } break;
+//
+//        case MessageQueue::REFRESH: {
+
+            handleRefresh();
+
+            const DisplayHardware& hw(graphicPlane(0).displayHardware());
+
+//            if (mDirtyRegion.isEmpty()) {
+//                return;
+//            }
+
+            if (CC_UNLIKELY(mHwWorkListDirty)) {
+                // build the h/w work list
+                handleWorkList();
+            }
+
+            if (CC_LIKELY(hw.canDraw())) {
+                // repaint the framebuffer (if needed)
+                handleRepaint();
+                // inform the h/w that we're done compositing
+                hw.compositionComplete();
+                postFramebuffer();
+            } else {
+                // pretend we did the post
+                hw.compositionComplete();
+            }
+
+        } break;
+    }
+}
+
 void SurfaceFlinger::postFramebuffer()
 {
-    // this should never happen. we do the flip anyways so we don't
-    // risk to cause a deadlock with hwc
-    ALOGW_IF(mSwapRegion.isEmpty(), "mSwapRegion is empty");
+    // mSwapRegion can be empty here is some cases, for instance if a hidden
+    // or fully transparent window is updating.
+    // in that case, we need to flip anyways to not risk a deadlock with
+    // h/w composer.
+
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const nsecs_t now = systemTime();
     mDebugInSwapBuffers = now;
     hw.flip(mSwapRegion);
+
+    size_t numLayers = mVisibleLayersSortedByZ.size();
+    for (size_t i = 0; i < numLayers; i++) {
+        mVisibleLayersSortedByZ[i]->onLayerDisplayed();
+    }
+
     mLastSwapBufferTime = systemTime() - now;
     mDebugInSwapBuffers = 0;
     mSwapRegion.clear();
@@ -711,13 +738,13 @@
 
 void SurfaceFlinger::handlePageFlip()
 {
-    bool visibleRegions = mVisibleRegionsDirty;
-    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-    visibleRegions |= lockPageFlip(currentLayers);
+    const DisplayHardware& hw = graphicPlane(0).displayHardware();
+    const Region screenRegion(hw.bounds());
 
-        const DisplayHardware& hw = graphicPlane(0).displayHardware();
-        const Region screenRegion(hw.bounds());
-        if (visibleRegions) {
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+    const bool visibleRegions = lockPageFlip(currentLayers);
+
+        if (visibleRegions || mVisibleRegionsDirty) {
             Region opaqueRegion;
             computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
 
@@ -764,7 +791,7 @@
 {
     const GraphicPlane& plane(graphicPlane(0));
     const Transform& planeTransform(plane.transform());
-    size_t count = currentLayers.size();
+    const size_t count = currentLayers.size();
     sp<LayerBase> const* layers = currentLayers.array();
     for (size_t i=0 ; i<count ; i++) {
         const sp<LayerBase>& layer(layers[i]);
@@ -772,6 +799,23 @@
     }
 }
 
+void SurfaceFlinger::handleRefresh()
+{
+    bool needInvalidate = false;
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        if (layer->onPreComposition()) {
+            needInvalidate = true;
+        }
+    }
+    if (needInvalidate) {
+        signalLayerUpdate();
+    }
+}
+
+
 void SurfaceFlinger::handleWorkList()
 {
     mHwWorkListDirty = false;
@@ -1169,7 +1213,7 @@
 {
     uint32_t old = android_atomic_or(flags, &mTransactionFlags);
     if ((old & flags)==0) { // wake the server up
-        signalEvent();
+        signalTransaction();
     }
     return old;
 }
@@ -1219,26 +1263,6 @@
     }
 }
 
-int SurfaceFlinger::setOrientation(DisplayID dpy,
-        int orientation, uint32_t flags)
-{
-    if (CC_UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
-        return BAD_VALUE;
-
-    Mutex::Autolock _l(mStateLock);
-    if (mCurrentState.orientation != orientation) {
-        if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
-            mCurrentState.orientationFlags = flags;
-            mCurrentState.orientation = orientation;
-            setTransactionFlags(eTransactionNeeded);
-            mTransactionCV.wait(mStateLock);
-        } else {
-            orientation = BAD_VALUE;
-        }
-    }
-    return orientation;
-}
-
 sp<ISurface> SurfaceFlinger::createSurface(
         ISurfaceComposerClient::surface_data_t* params,
         const String8& name,
@@ -1440,14 +1464,14 @@
 {
     // this may be called by a signal handler, we can't do too much in here
     android_atomic_or(eConsoleReleased, &mConsoleSignals);
-    signalEvent();
+    signalTransaction();
 }
 
 void SurfaceFlinger::screenAcquired(int dpy)
 {
     // this may be called by a signal handler, we can't do too much in here
     android_atomic_or(eConsoleAcquired, &mConsoleSignals);
-    signalEvent();
+    signalTransaction();
 }
 
 status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
@@ -1463,14 +1487,6 @@
                 IPCThreadState::self()->getCallingUid());
         result.append(buffer);
     } else {
-
-        // figure out if we're stuck somewhere
-        const nsecs_t now = systemTime();
-        const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
-        const nsecs_t inTransaction(mDebugInTransaction);
-        nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
-        nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
-
         // Try to get the main lock, but don't insist if we can't
         // (this would indicate SF is stuck, but we want to be able to
         // print something in dumpsys).
@@ -1486,111 +1502,35 @@
             result.append(buffer);
         }
 
-        /*
-         * Dump the visible layer list
-         */
-        const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
-        const size_t count = currentLayers.size();
-        snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
-        result.append(buffer);
-        for (size_t i=0 ; i<count ; i++) {
-            const sp<LayerBase>& layer(currentLayers[i]);
-            layer->dump(result, buffer, SIZE);
-            const Layer::State& s(layer->drawingState());
-            s.transparentRegion.dump(result, "transparentRegion");
-            layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
-            layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
+        bool dumpAll = true;
+        size_t index = 0;
+        size_t numArgs = args.size();
+        if (numArgs) {
+            dumpAll = false;
+
+            if ((index < numArgs) &&
+                    (args[index] == String16("--list"))) {
+                index++;
+                listLayersLocked(args, index, result, buffer, SIZE);
+            }
+
+            if ((index < numArgs) &&
+                    (args[index] == String16("--latency"))) {
+                index++;
+                dumpStatsLocked(args, index, result, buffer, SIZE);
+            }
+
+            if ((index < numArgs) &&
+                    (args[index] == String16("--latency-clear"))) {
+                index++;
+                clearStatsLocked(args, index, result, buffer, SIZE);
+            }
         }
 
-        /*
-         * Dump the layers in the purgatory
-         */
-
-        const size_t purgatorySize = mLayerPurgatory.size();
-        snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
-        result.append(buffer);
-        for (size_t i=0 ; i<purgatorySize ; i++) {
-            const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
-            layer->shortDump(result, buffer, SIZE);
+        if (dumpAll) {
+            dumpAllLocked(result, buffer, SIZE);
         }
 
-        /*
-         * Dump SurfaceFlinger global state
-         */
-
-        snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
-        result.append(buffer);
-
-        const GLExtensions& extensions(GLExtensions::getInstance());
-        snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
-                extensions.getVendor(),
-                extensions.getRenderer(),
-                extensions.getVersion());
-        result.append(buffer);
-
-        snprintf(buffer, SIZE, "EGL : %s\n",
-                eglQueryString(graphicPlane(0).getEGLDisplay(),
-                        EGL_VERSION_HW_ANDROID));
-        result.append(buffer);
-
-        snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
-        result.append(buffer);
-
-        mWormholeRegion.dump(result, "WormholeRegion");
-        const DisplayHardware& hw(graphicPlane(0).displayHardware());
-        snprintf(buffer, SIZE,
-                "  orientation=%d, canDraw=%d\n",
-                mCurrentState.orientation, hw.canDraw());
-        result.append(buffer);
-        snprintf(buffer, SIZE,
-                "  last eglSwapBuffers() time: %f us\n"
-                "  last transaction time     : %f us\n"
-                "  refresh-rate              : %f fps\n"
-                "  x-dpi                     : %f\n"
-                "  y-dpi                     : %f\n",
-                mLastSwapBufferTime/1000.0,
-                mLastTransactionTime/1000.0,
-                hw.getRefreshRate(),
-                hw.getDpiX(),
-                hw.getDpiY());
-        result.append(buffer);
-
-        if (inSwapBuffersDuration || !locked) {
-            snprintf(buffer, SIZE, "  eglSwapBuffers time: %f us\n",
-                    inSwapBuffersDuration/1000.0);
-            result.append(buffer);
-        }
-
-        if (inTransactionDuration || !locked) {
-            snprintf(buffer, SIZE, "  transaction time: %f us\n",
-                    inTransactionDuration/1000.0);
-            result.append(buffer);
-        }
-
-        /*
-         * VSYNC state
-         */
-        mEventThread->dump(result, buffer, SIZE);
-
-        /*
-         * Dump HWComposer state
-         */
-        HWComposer& hwc(hw.getHwComposer());
-        snprintf(buffer, SIZE, "h/w composer state:\n");
-        result.append(buffer);
-        snprintf(buffer, SIZE, "  h/w composer %s and %s\n",
-                hwc.initCheck()==NO_ERROR ? "present" : "not present",
-                (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
-        result.append(buffer);
-        hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ);
-
-        /*
-         * Dump gralloc state
-         */
-        const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
-        alloc.dump(result);
-        hw.dump(result);
-
         if (locked) {
             mStateLock.unlock();
         }
@@ -1599,6 +1539,170 @@
     return NO_ERROR;
 }
 
+void SurfaceFlinger::listLayersLocked(const Vector<String16>& args, size_t& index,
+        String8& result, char* buffer, size_t SIZE) const
+{
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        snprintf(buffer, SIZE, "%s\n", layer->getName().string());
+        result.append(buffer);
+    }
+}
+
+void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
+        String8& result, char* buffer, size_t SIZE) const
+{
+    String8 name;
+    if (index < args.size()) {
+        name = String8(args[index]);
+        index++;
+    }
+
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        if (name.isEmpty()) {
+            snprintf(buffer, SIZE, "%s\n", layer->getName().string());
+            result.append(buffer);
+        }
+        if (name.isEmpty() || (name == layer->getName())) {
+            layer->dumpStats(result, buffer, SIZE);
+        }
+    }
+}
+
+void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
+        String8& result, char* buffer, size_t SIZE) const
+{
+    String8 name;
+    if (index < args.size()) {
+        name = String8(args[index]);
+        index++;
+    }
+
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        if (name.isEmpty() || (name == layer->getName())) {
+            layer->clearStats();
+        }
+    }
+}
+
+void SurfaceFlinger::dumpAllLocked(
+        String8& result, char* buffer, size_t SIZE) const
+{
+    // figure out if we're stuck somewhere
+    const nsecs_t now = systemTime();
+    const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
+    const nsecs_t inTransaction(mDebugInTransaction);
+    nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
+    nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
+
+    /*
+     * Dump the visible layer list
+     */
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    const size_t count = currentLayers.size();
+    snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
+    result.append(buffer);
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        layer->dump(result, buffer, SIZE);
+    }
+
+    /*
+     * Dump the layers in the purgatory
+     */
+
+    const size_t purgatorySize = mLayerPurgatory.size();
+    snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
+    result.append(buffer);
+    for (size_t i=0 ; i<purgatorySize ; i++) {
+        const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
+        layer->shortDump(result, buffer, SIZE);
+    }
+
+    /*
+     * Dump SurfaceFlinger global state
+     */
+
+    snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
+    result.append(buffer);
+
+    const GLExtensions& extensions(GLExtensions::getInstance());
+    snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
+            extensions.getVendor(),
+            extensions.getRenderer(),
+            extensions.getVersion());
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "EGL : %s\n",
+            eglQueryString(graphicPlane(0).getEGLDisplay(),
+                    EGL_VERSION_HW_ANDROID));
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
+    result.append(buffer);
+
+    mWormholeRegion.dump(result, "WormholeRegion");
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    snprintf(buffer, SIZE,
+            "  orientation=%d, canDraw=%d\n",
+            mCurrentState.orientation, hw.canDraw());
+    result.append(buffer);
+    snprintf(buffer, SIZE,
+            "  last eglSwapBuffers() time: %f us\n"
+            "  last transaction time     : %f us\n"
+            "  transaction-flags         : %08x\n"
+            "  refresh-rate              : %f fps\n"
+            "  x-dpi                     : %f\n"
+            "  y-dpi                     : %f\n",
+            mLastSwapBufferTime/1000.0,
+            mLastTransactionTime/1000.0,
+            mTransactionFlags,
+            hw.getRefreshRate(),
+            hw.getDpiX(),
+            hw.getDpiY());
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "  eglSwapBuffers time: %f us\n",
+            inSwapBuffersDuration/1000.0);
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "  transaction time: %f us\n",
+            inTransactionDuration/1000.0);
+    result.append(buffer);
+
+    /*
+     * VSYNC state
+     */
+    mEventThread->dump(result, buffer, SIZE);
+
+    /*
+     * Dump HWComposer state
+     */
+    HWComposer& hwc(hw.getHwComposer());
+    snprintf(buffer, SIZE, "h/w composer state:\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "  h/w composer %s and %s\n",
+            hwc.initCheck()==NO_ERROR ? "present" : "not present",
+                    (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
+    result.append(buffer);
+    hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ);
+
+    /*
+     * Dump gralloc state
+     */
+    const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+    alloc.dump(result);
+    hw.dump(result);
+}
+
 status_t SurfaceFlinger::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -1689,6 +1793,7 @@
                 reply->writeInt32(0);
                 reply->writeInt32(mDebugRegion);
                 reply->writeInt32(mDebugBackground);
+                reply->writeInt32(mDebugDisableHWC);
                 return NO_ERROR;
             case 1013: {
                 Mutex::Autolock _l(mStateLock);
@@ -1705,7 +1810,7 @@
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const Rect bounds(hw.getBounds());
     setInvalidateRegion(Region(bounds));
-    signalEvent();
+    signalTransaction();
 }
 
 void SurfaceFlinger::setInvalidateRegion(const Region& reg) {
@@ -2181,7 +2286,7 @@
 
     // make sure to redraw the whole screen when the animation is done
     mDirtyRegion.set(hw.bounds());
-    signalEvent();
+    signalTransaction();
 
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7f6c90c..fcd9361 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -170,7 +170,6 @@
     virtual void                        bootFinished();
     virtual void                        setTransactionState(const Vector<ComposerState>& state,
                                                             int orientation, uint32_t flags);
-    virtual int                         setOrientation(DisplayID dpy, int orientation, uint32_t flags);
     virtual bool                        authenticateSurfaceTexture(const sp<ISurfaceTexture>& surface) const;
     virtual sp<IDisplayEventConnection> createDisplayEventConnection();
 
@@ -191,6 +190,8 @@
             status_t renderScreenToTextureLocked(DisplayID dpy,
                     GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
 
+            void onMessageReceived(int32_t what);
+
             status_t postMessageAsync(const sp<MessageBase>& msg,
                     nsecs_t reltime=0, uint32_t flags = 0);
 
@@ -284,7 +285,10 @@
 public:     // hack to work around gcc 4.0.3 bug
     const GraphicPlane&     graphicPlane(int dpy) const;
           GraphicPlane&     graphicPlane(int dpy);
-          void              signalEvent();
+
+          void              signalTransaction();
+          void              signalLayerUpdate();
+          void              signalRefresh();
           void              repaintEverything();
 
 private:
@@ -301,6 +305,7 @@
             void        handlePageFlip();
             bool        lockPageFlip(const LayerVector& currentLayers);
             void        unlockPageFlip(const LayerVector& currentLayers);
+            void        handleRefresh();
             void        handleWorkList();
             void        handleRepaint();
             void        postFramebuffer();
@@ -337,6 +342,13 @@
             void        debugFlashRegions();
             void        drawWormhole() const;
            
+            void listLayersLocked(const Vector<String16>& args, size_t& index,
+                    String8& result, char* buffer, size_t SIZE) const;
+            void dumpStatsLocked(const Vector<String16>& args, size_t& index,
+                    String8& result, char* buffer, size_t SIZE) const;
+            void clearStatsLocked(const Vector<String16>& args, size_t& index,
+                    String8& result, char* buffer, size_t SIZE) const;
+            void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const;
 
     mutable     MessageQueue    mEventQueue;
 
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 259b937..49e8e63 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -94,6 +94,10 @@
             *outTransform = orientation;
         }
         switch(api) {
+            case NATIVE_WINDOW_API_CPU:
+                // SurfaceTextureClient supports only 2 buffers for CPU connections
+                this->setBufferCountServer(2);
+                break;
             case NATIVE_WINDOW_API_MEDIA:
             case NATIVE_WINDOW_API_CAMERA:
                 // Camera preview and videos are rate-limited on the producer
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index 4f79080..b0d54c4 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -55,6 +55,8 @@
     loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver,
             &myDisplayEvent);
 
+    myDisplayEvent.setVsyncRate(1);
+
     do {
         //printf("about to poll...\n");
         int32_t ret = loop->pollOnce(-1);
diff --git a/services/tests/servicestests/res/raw/netstats_uid_v4 b/services/tests/servicestests/res/raw/netstats_uid_v4
new file mode 100644
index 0000000..e75fc1c
--- /dev/null
+++ b/services/tests/servicestests/res/raw/netstats_uid_v4
Binary files differ
diff --git a/services/tests/servicestests/res/raw/netstats_v1 b/services/tests/servicestests/res/raw/netstats_v1
new file mode 100644
index 0000000..e80860a
--- /dev/null
+++ b/services/tests/servicestests/res/raw/netstats_v1
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 36a2567..e863f8b 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -21,7 +21,6 @@
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
-import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -29,6 +28,8 @@
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
+import static android.net.TrafficStats.KB_IN_BYTES;
+import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT;
@@ -101,10 +102,6 @@
     private static final long TEST_START = 1194220800000L;
     private static final String TEST_IFACE = "test0";
 
-    private static final long KB_IN_BYTES = 1024;
-    private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
-    private static final long GB_IN_BYTES = MB_IN_BYTES * 1024;
-
     private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi();
 
     private BroadcastInterceptingContext mServiceContext;
@@ -256,41 +253,49 @@
     }
 
     public void testPidForegroundCombined() throws Exception {
+        IdleFuture idle;
+
         // push all uid into background
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
         mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, false);
-        waitUntilIdle();
+        idle.get();
         assertFalse(mService.isUidForeground(UID_A));
         assertFalse(mService.isUidForeground(UID_B));
 
         // push one of the shared pids into foreground
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
-        waitUntilIdle();
+        idle.get();
         assertTrue(mService.isUidForeground(UID_A));
         assertFalse(mService.isUidForeground(UID_B));
 
         // and swap another uid into foreground
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
         mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, true);
-        waitUntilIdle();
+        idle.get();
         assertFalse(mService.isUidForeground(UID_A));
         assertTrue(mService.isUidForeground(UID_B));
 
         // push both pid into foreground
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
-        waitUntilIdle();
+        idle.get();
         assertTrue(mService.isUidForeground(UID_A));
 
         // pull one out, should still be foreground
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
-        waitUntilIdle();
+        idle.get();
         assertTrue(mService.isUidForeground(UID_A));
 
         // pull final pid out, should now be background
+        idle = expectIdle();
         mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
-        waitUntilIdle();
+        idle.get();
         assertFalse(mService.isUidForeground(UID_A));
     }
 
@@ -434,7 +439,7 @@
         final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
 
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 5, 1024L, 1024L, SNOOZE_NEVER, false);
+                sTemplateWifi, 5, 1024L, 1024L, false);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertTimeEquals(expectedCycle, actualCycle);
     }
@@ -445,7 +450,7 @@
         final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
 
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 20, 1024L, 1024L, SNOOZE_NEVER, false);
+                sTemplateWifi, 20, 1024L, 1024L, false);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertTimeEquals(expectedCycle, actualCycle);
     }
@@ -456,7 +461,7 @@
         final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
 
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER, false);
+                sTemplateWifi, 30, 1024L, 1024L, false);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertTimeEquals(expectedCycle, actualCycle);
     }
@@ -467,14 +472,14 @@
         final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
 
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER, false);
+                sTemplateWifi, 30, 1024L, 1024L, false);
         final long actualCycle = computeLastCycleBoundary(currentTime, policy);
         assertTimeEquals(expectedCycle, actualCycle);
     }
 
     public void testNextCycleSane() throws Exception {
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, false);
+                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
         final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
 
         // walk forwards, ensuring that cycle boundaries don't get stuck
@@ -489,7 +494,7 @@
 
     public void testLastCycleSane() throws Exception {
         final NetworkPolicy policy = new NetworkPolicy(
-                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, false);
+                sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
         final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
 
         // walk backwards, ensuring that cycle boundaries look sane
@@ -547,7 +552,7 @@
 
         replay();
         setNetworkPolicies(new NetworkPolicy(
-                sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, SNOOZE_NEVER, false));
+                sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
         future.get();
         verifyAndReset();
     }
@@ -604,9 +609,8 @@
             future = expectMeteredIfacesChanged();
 
             replay();
-            setNetworkPolicies(
-                    new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES,
-                            SNOOZE_NEVER, false));
+            setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES,
+                    2 * MB_IN_BYTES, false));
             future.get();
             verifyAndReset();
         }
@@ -698,7 +702,7 @@
             tagFuture = expectEnqueueNotification();
 
             replay();
-            mService.snoozePolicy(sTemplateWifi);
+            mService.snoozeLimit(sTemplateWifi);
             assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get());
             future.get();
             verifyAndReset();
@@ -736,9 +740,8 @@
             future = expectMeteredIfacesChanged(TEST_IFACE);
 
             replay();
-            setNetworkPolicies(
-                    new NetworkPolicy(sTemplateWifi, CYCLE_DAY, WARNING_DISABLED, LIMIT_DISABLED,
-                            SNOOZE_NEVER, true));
+            setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, WARNING_DISABLED,
+                    LIMIT_DISABLED, true));
             future.get();
             verifyAndReset();
         }
@@ -890,10 +893,10 @@
     /**
      * Wait until {@link #mService} internal {@link Handler} is idle.
      */
-    private void waitUntilIdle() throws Exception {
+    private IdleFuture expectIdle() {
         final IdleFuture future = new IdleFuture();
         mService.addIdleHandler(future);
-        future.get();
+        return future;
     }
 
     private static void assertTimeEquals(long expected, long actual) {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 90b5a2e..daf20183 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -31,6 +31,7 @@
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
 import static android.net.NetworkTemplate.buildTemplateWifi;
+import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UID_REMOVED;
 import static android.net.TrafficStats.UID_TETHERING;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
@@ -39,6 +40,7 @@
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
 import static org.easymock.EasyMock.anyLong;
+import static org.easymock.EasyMock.aryEq;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.eq;
@@ -63,10 +65,12 @@
 import android.telephony.TelephonyManager;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
 import android.util.TrustedTime;
 
 import com.android.server.net.NetworkStatsService;
 import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
+import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
 
 import org.easymock.Capture;
 import org.easymock.EasyMock;
@@ -282,13 +286,6 @@
         mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
         verifyAndReset();
 
-        // talk with zombie service to assert stats have gone; and assert that
-        // we persisted them to file.
-        expectDefaultSettings();
-        replay();
-        assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-        verifyAndReset();
-
         assertStatsFilesExist(true);
 
         // boot through serviceReady() again
@@ -319,6 +316,8 @@
 
     }
 
+    // TODO: simulate reboot to test bucket resize
+    @Suppress
     public void testStatsBucketResize() throws Exception {
         NetworkStatsHistory history = null;
 
@@ -602,7 +601,6 @@
         assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
 
         verifyAndReset();
-
     }
 
     public void testSummaryForAllUid() throws Exception {
@@ -755,11 +753,15 @@
         expectDefaultSettings();
         expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
                 .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
-        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
-                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L));
+
+        final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1)
+                .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
         final String[] tetherIfacePairs = new String[] { TEST_IFACE, "wlan0" };
-        expectNetworkStatsPoll(tetherIfacePairs, new NetworkStats(getElapsedRealtime(), 1)
-                .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L));
+        final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
+                .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L);
+
+        expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats);
+        expectNetworkStatsPoll();
 
         replay();
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -808,6 +810,9 @@
 
     private void expectNetworkState(NetworkState... state) throws Exception {
         expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+
+        final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null;
+        expect(mConnManager.getActiveLinkProperties()).andReturn(linkProp).atLeastOnce();
     }
 
     private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
@@ -815,23 +820,35 @@
     }
 
     private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
+        expectNetworkStatsUidDetail(detail, new String[0], new NetworkStats(0L, 0));
+    }
+
+    private void expectNetworkStatsUidDetail(
+            NetworkStats detail, String[] tetherIfacePairs, NetworkStats tetherStats)
+            throws Exception {
         expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce();
+
+        // also include tethering details, since they are folded into UID
+        expect(mConnManager.getTetheredIfacePairs()).andReturn(tetherIfacePairs).atLeastOnce();
+        expect(mNetManager.getNetworkStatsTethering(aryEq(tetherIfacePairs)))
+                .andReturn(tetherStats).atLeastOnce();
     }
 
     private void expectDefaultSettings() throws Exception {
         expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
     }
 
-    private void expectSettings(long persistThreshold, long bucketDuration, long maxHistory)
+    private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
             throws Exception {
         expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
-        expect(mSettings.getPersistThreshold()).andReturn(persistThreshold).anyTimes();
-        expect(mSettings.getNetworkBucketDuration()).andReturn(bucketDuration).anyTimes();
-        expect(mSettings.getNetworkMaxHistory()).andReturn(maxHistory).anyTimes();
-        expect(mSettings.getUidBucketDuration()).andReturn(bucketDuration).anyTimes();
-        expect(mSettings.getUidMaxHistory()).andReturn(maxHistory).anyTimes();
-        expect(mSettings.getTagMaxHistory()).andReturn(maxHistory).anyTimes();
         expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
+        expect(mSettings.getGlobalAlertBytes()).andReturn(MB_IN_BYTES).anyTimes();
+        expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes();
+
+        final Config config = new Config(bucketDuration, persistBytes, deleteAge, deleteAge);
+        expect(mSettings.getDevConfig()).andReturn(config).anyTimes();
+        expect(mSettings.getUidConfig()).andReturn(config).anyTimes();
+        expect(mSettings.getUidTagConfig()).andReturn(config).anyTimes();
     }
 
     private void expectCurrentTime() throws Exception {
@@ -843,27 +860,16 @@
     }
 
     private void expectNetworkStatsPoll() throws Exception {
-        expectNetworkStatsPoll(new String[0], new NetworkStats(getElapsedRealtime(), 0));
-    }
-
-    private void expectNetworkStatsPoll(String[] tetherIfacePairs, NetworkStats tetherStats)
-            throws Exception {
         mNetManager.setGlobalAlert(anyLong());
         expectLastCall().anyTimes();
-        expect(mConnManager.getTetheredIfacePairs()).andReturn(tetherIfacePairs).anyTimes();
-        expect(mNetManager.getNetworkStatsTethering(eq(tetherIfacePairs)))
-                .andReturn(tetherStats).anyTimes();
     }
 
     private void assertStatsFilesExist(boolean exist) {
-        final File networkFile = new File(mStatsDir, "netstats.bin");
-        final File uidFile = new File(mStatsDir, "netstats_uid.bin");
+        final File basePath = new File(mStatsDir, "netstats");
         if (exist) {
-            assertTrue(networkFile.exists());
-            assertTrue(uidFile.exists());
+            assertTrue(basePath.list().length > 0);
         } else {
-            assertFalse(networkFile.exists());
-            assertFalse(uidFile.exists());
+            assertTrue(basePath.list().length == 0);
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
new file mode 100644
index 0000000..7f05f56
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkIdentity;
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.frameworks.servicestests.R;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+/**
+ * Tests for {@link NetworkStatsCollection}.
+ */
+@MediumTest
+public class NetworkStatsCollectionTest extends AndroidTestCase {
+    
+    private static final String TEST_FILE = "test.bin";
+    private static final String TEST_IMSI = "310260000000000";
+
+    public void testReadLegacyNetwork() throws Exception {
+        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+        stageFile(R.raw.netstats_v1, testFile);
+
+        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
+        collection.readLegacyNetwork(testFile);
+        
+        // verify that history read correctly
+        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+                636014522L, 709291L, 88037144L, 518820L);
+
+        // now export into a unified format
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        collection.write(new DataOutputStream(bos));
+
+        // clear structure completely
+        collection.reset();
+        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+                0L, 0L, 0L, 0L);
+
+        // and read back into structure, verifying that totals are same
+        collection.read(new ByteArrayInputStream(bos.toByteArray()));
+        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+                636014522L, 709291L, 88037144L, 518820L);
+    }
+
+    public void testReadLegacyUid() throws Exception {
+        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+        stageFile(R.raw.netstats_uid_v4, testFile);
+
+        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
+        collection.readLegacyUid(testFile, false);
+
+        // verify that history read correctly
+        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+                637073904L, 711398L, 88342093L, 521006L);
+
+        // now export into a unified format
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        collection.write(new DataOutputStream(bos));
+
+        // clear structure completely
+        collection.reset();
+        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+                0L, 0L, 0L, 0L);
+
+        // and read back into structure, verifying that totals are same
+        collection.read(new ByteArrayInputStream(bos.toByteArray()));
+        assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+                637073904L, 711398L, 88342093L, 521006L);
+    }
+
+    public void testReadLegacyUidTags() throws Exception {
+        final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+        stageFile(R.raw.netstats_uid_v4, testFile);
+
+        final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
+        collection.readLegacyUid(testFile, true);
+
+        // verify that history read correctly
+        assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
+                77017831L, 100995L, 35436758L, 92344L);
+
+        // now export into a unified format
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        collection.write(new DataOutputStream(bos));
+
+        // clear structure completely
+        collection.reset();
+        assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
+                0L, 0L, 0L, 0L);
+
+        // and read back into structure, verifying that totals are same
+        collection.read(new ByteArrayInputStream(bos.toByteArray()));
+        assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
+                77017831L, 100995L, 35436758L, 92344L);
+    }
+
+    /**
+     * Copy a {@link Resources#openRawResource(int)} into {@link File} for
+     * testing purposes.
+     */
+    private void stageFile(int rawId, File file) throws Exception {
+        new File(file.getParent()).mkdirs();
+        InputStream in = null;
+        OutputStream out = null;
+        try {
+            in = getContext().getResources().openRawResource(rawId);
+            out = new FileOutputStream(file);
+            Streams.copy(in, out);
+        } finally {
+            IoUtils.closeQuietly(in);
+            IoUtils.closeQuietly(out);
+        }
+    }
+
+    public static NetworkIdentitySet buildWifiIdent() {
+        final NetworkIdentitySet set = new NetworkIdentitySet();
+        set.add(new NetworkIdentity(ConnectivityManager.TYPE_WIFI, 0, null, false));
+        return set;
+    }
+
+    private static void assertSummaryTotal(NetworkStatsCollection collection,
+            NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
+        final NetworkStats.Entry entry = collection.getSummary(
+                template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null);
+        assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
+    }
+
+    private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
+            NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
+        final NetworkStats.Entry entry = collection.getSummary(
+                template, Long.MIN_VALUE, Long.MAX_VALUE).getTotalIncludingTags(null);
+        assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
+    }
+
+    private static void assertEntry(
+            NetworkStats.Entry entry, long rxBytes, long rxPackets, long txBytes, long txPackets) {
+        assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+        assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
+        assertEquals("unexpected txBytes", txBytes, entry.txBytes);
+        assertEquals("unexpected txPackets", txPackets, entry.txPackets);
+    }
+}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 5da3d97..24a4876 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1438,7 +1438,8 @@
      *            phoneNumber doesn't have the country code.
      * @param defaultCountryIso
      *            the ISO 3166-1 two letters country code whose convention will
-     *            be used if the phoneNumberE164 is null or invalid.
+     *            be used if the phoneNumberE164 is null or invalid, or if phoneNumber
+     *            contains IDD.
      * @return the formatted number if the given number has been formatted,
      *            otherwise, return the given number.
      *
@@ -1457,9 +1458,13 @@
         if (phoneNumberE164 != null && phoneNumberE164.length() >= 2
                 && phoneNumberE164.charAt(0) == '+') {
             try {
-                PhoneNumber pn = util.parse(phoneNumberE164, defaultCountryIso);
+                // The number to be parsed is in E164 format, so the default region used doesn't
+                // matter.
+                PhoneNumber pn = util.parse(phoneNumberE164, "ZZ");
                 String regionCode = util.getRegionCodeForNumber(pn);
-                if (!TextUtils.isEmpty(regionCode)) {
+                if (!TextUtils.isEmpty(regionCode) &&
+                    // This makes sure phoneNumber doesn't contain an IDD
+                    normalizeNumber(phoneNumber).indexOf(phoneNumberE164.substring(1)) <= 0) {
                     defaultCountryIso = regionCode;
                 }
             } catch (NumberParseException e) {
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 3128592..1049669 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -47,6 +47,9 @@
         "none", "poor", "moderate", "good", "great"
     };
 
+    /** @hide */
+    public static final int INVALID_SNR = 0x7FFFFFFF;
+
     private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mGsmBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
     private int mCdmaDbm;   // This value is the RSSI value
@@ -96,7 +99,7 @@
         mLteSignalStrength = -1;
         mLteRsrp = -1;
         mLteRsrq = -1;
-        mLteRssnr = -1;
+        mLteRssnr = INVALID_SNR;
         mLteCqi = -1;
         isGsm = true;
     }
@@ -136,7 +139,8 @@
             int evdoDbm, int evdoEcio, int evdoSnr,
             boolean gsm) {
         this(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
-                evdoDbm, evdoEcio, evdoSnr, -1, -1, -1, -1, -1, gsm);
+                evdoDbm, evdoEcio, evdoSnr, -1, -1,
+                -1, INVALID_SNR, -1, gsm);
     }
 
     /**
@@ -289,10 +293,11 @@
         int level;
 
         if (isGsm) {
+            // TODO Need solve the discrepancy of invalid values between
+            // RIL_LTE_SignalStrength and here.
             if ((mLteSignalStrength == -1)
                     && (mLteRsrp == -1)
                     && (mLteRsrq == -1)
-                    && (mLteRssnr == -1)
                     && (mLteCqi == -1)) {
                 level = getGsmLevel();
             } else {
@@ -327,7 +332,6 @@
             if ((mLteSignalStrength == -1)
                     && (mLteRsrp == -1)
                     && (mLteRsrq == -1)
-                    && (mLteRssnr == -1)
                     && (mLteCqi == -1)) {
                 asuLevel = getGsmAsuLevel();
             } else {
@@ -363,7 +367,6 @@
             if ((mLteSignalStrength == -1)
                     && (mLteRsrp == -1)
                     && (mLteRsrq == -1)
-                    && (mLteRssnr == -1)
                     && (mLteCqi == -1)) {
                 dBm = getGsmDbm();
             } else {
@@ -566,16 +569,31 @@
      */
     public int getLteLevel() {
         int levelLteRsrp = 0;
+        int levelLteRssnr = 0;
 
         if (mLteRsrp == -1) levelLteRsrp = 0;
-        else if (mLteRsrp >= -90) levelLteRsrp = SIGNAL_STRENGTH_GREAT;
-        else if (mLteRsrp >= -100) levelLteRsrp = SIGNAL_STRENGTH_GOOD;
-        else if (mLteRsrp >= -110) levelLteRsrp = SIGNAL_STRENGTH_MODERATE;
-        else if (mLteRsrp >= -118) levelLteRsrp = SIGNAL_STRENGTH_POOR;
-        else levelLteRsrp = 0;
+        else if (mLteRsrp >= -95) levelLteRsrp = SIGNAL_STRENGTH_GREAT;
+        else if (mLteRsrp >= -105) levelLteRsrp = SIGNAL_STRENGTH_GOOD;
+        else if (mLteRsrp >= -115) levelLteRsrp = SIGNAL_STRENGTH_MODERATE;
+        else levelLteRsrp = SIGNAL_STRENGTH_POOR;
 
-        if (DBG) log("Lte level: "+levelLteRsrp);
-        return levelLteRsrp;
+        if (mLteRssnr == INVALID_SNR) levelLteRssnr = 0;
+        else if (mLteRssnr >= 45) levelLteRssnr = SIGNAL_STRENGTH_GREAT;
+        else if (mLteRssnr >= 10) levelLteRssnr = SIGNAL_STRENGTH_GOOD;
+        else if (mLteRssnr >= -30) levelLteRssnr = SIGNAL_STRENGTH_MODERATE;
+        else levelLteRssnr = SIGNAL_STRENGTH_POOR;
+
+        int level;
+        if (mLteRsrp == -1)
+            level = levelLteRssnr;
+        else if (mLteRssnr == INVALID_SNR)
+            level = levelLteRsrp;
+        else
+            level = (levelLteRssnr < levelLteRsrp) ? levelLteRssnr : levelLteRsrp;
+
+        if (DBG) log("Lte rsrp level: "+levelLteRsrp
+                + " snr level: " + levelLteRssnr + " level: " + level);
+        return level;
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index 893d7a8..35cdf9bd 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -715,4 +715,7 @@
                 "' lteOnCdmaProductType='" + sLteOnCdmaProductType + "'");
         return retVal;
     }
+
+    @Override
+    public void testingEmergencyCall() {}
 }
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 3dd57ee..f825f31 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -373,10 +373,19 @@
         AudioManager audioManager = (AudioManager)
                 context.getSystemService(Context.AUDIO_SERVICE);
 
-        int mode = AudioManager.MODE_NORMAL;
+        // change the audio mode and request/abandon audio focus according to phone state,
+        // but only on audio mode transitions
         switch (getState()) {
             case RINGING:
-                mode = AudioManager.MODE_RINGTONE;
+                if (audioManager.getMode() != AudioManager.MODE_RINGTONE) {
+                    // only request audio focus if the ringtone is going to be heard
+                    if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {
+                        if (VDBG) Log.d(LOG_TAG, "requestAudioFocus on STREAM_RING");
+                        audioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
+                                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+                    }
+                    audioManager.setMode(AudioManager.MODE_RINGTONE);
+                }
                 break;
             case OFFHOOK:
                 Phone offhookPhone = getFgPhone();
@@ -386,18 +395,28 @@
                     offhookPhone = getBgPhone();
                 }
 
+                int newAudioMode = AudioManager.MODE_IN_CALL;
                 if (offhookPhone instanceof SipPhone) {
-                    // enable IN_COMMUNICATION audio mode for sipPhone
-                    mode = AudioManager.MODE_IN_COMMUNICATION;
-                } else {
-                    // enable IN_CALL audio mode for telephony
-                    mode = AudioManager.MODE_IN_CALL;
+                    // enable IN_COMMUNICATION audio mode instead for sipPhone
+                    newAudioMode = AudioManager.MODE_IN_COMMUNICATION;
+                }
+                if (audioManager.getMode() != newAudioMode) {
+                    // request audio focus before setting the new mode
+                    if (VDBG) Log.d(LOG_TAG, "requestAudioFocus on STREAM_VOICE_CALL");
+                    audioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
+                            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+                    audioManager.setMode(newAudioMode);
+                }
+                break;
+            case IDLE:
+                if (audioManager.getMode() != AudioManager.MODE_NORMAL) {
+                    audioManager.setMode(AudioManager.MODE_NORMAL);
+                    if (VDBG) Log.d(LOG_TAG, "abandonAudioFocus");
+                    // abandon audio focus after the mode has been set back to normal
+                    audioManager.abandonAudioFocusForCall();
                 }
                 break;
         }
-        // calling audioManager.setMode() multiple times in a short period of
-        // time seems to break the audio recorder in in-call mode
-        if (audioManager.getMode() != mode) audioManager.setMode(mode);
     }
 
     private Context getContext() {
diff --git a/telephony/java/com/android/internal/telephony/CallTracker.java b/telephony/java/com/android/internal/telephony/CallTracker.java
index 31f9e18..958481c 100644
--- a/telephony/java/com/android/internal/telephony/CallTracker.java
+++ b/telephony/java/com/android/internal/telephony/CallTracker.java
@@ -19,6 +19,8 @@
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemProperties;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.telephony.CommandException;
@@ -116,6 +118,48 @@
         return pendingOperations == 0;
     }
 
+    /**
+     * Routine called from dial to check if the number is a test Emergency number
+     * and if so remap the number. This allows a short emergency number to be remapped
+     * to a regular number for testing how the frameworks handles emergency numbers
+     * without actually calling an emergency number.
+     *
+     * This is not a full test and is not a substitute for testing real emergency
+     * numbers but can be useful.
+     *
+     * To use this feature set a system property ril.test.emergencynumber to a pair of
+     * numbers separated by a colon. If the first number matches the number parameter
+     * this routine returns the second number. Example:
+     *
+     * ril.test.emergencynumber=112:1-123-123-45678
+     *
+     * To test Dial 112 take call then hang up on MO device to enter ECM
+     * see RIL#processSolicited RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
+     *
+     * @param number to test if it should be remapped
+     * @return the same number or the remapped number.
+     */
+    protected String checkForTestEmergencyNumber(String dialString) {
+        String testEn = SystemProperties.get("ril.test.emergencynumber");
+        if (DBG_POLL) {
+            log("checkForTestEmergencyNumber: dialString=" + dialString +
+                " testEn=" + testEn);
+        }
+        if (!TextUtils.isEmpty(testEn)) {
+            String values[] = testEn.split(":");
+            log("checkForTestEmergencyNumber: values.length=" + values.length);
+            if (values.length == 2) {
+                if (values[0].equals(
+                        android.telephony.PhoneNumberUtils.stripSeparators(dialString))) {
+                    cm.testingEmergencyCall();
+                    log("checkForTestEmergencyNumber: remap " +
+                            dialString + " to " + values[1]);
+                    dialString = values[1];
+                }
+            }
+        }
+        return dialString;
+    }
 
     //***** Overridden from Handler
     public abstract void handleMessage (Message msg);
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index ee39850..f7757b3 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -93,11 +93,6 @@
     static final int USSD_MODE_NOTIFY       = 0;
     static final int USSD_MODE_REQUEST      = 1;
 
-    // SIM Refresh results, passed up from RIL.
-    static final int SIM_REFRESH_FILE_UPDATED   = 0;  // Single file updated
-    static final int SIM_REFRESH_INIT           = 1;  // SIM initialized; reload all
-    static final int SIM_REFRESH_RESET          = 2;  // SIM reset; may be locked
-
     // GSM SMS fail cause for acknowledgeLastIncomingSMS. From TS 23.040, 9.2.3.22.
     static final int GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED    = 0xD3;
     static final int GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY       = 0xD4;
@@ -764,6 +759,15 @@
      *  retMsg.obj = AsyncResult ar
      *  ar.exception carries exception on failure
      *  ar.userObject contains the orignal value of result.obj
+     *  ar.result is String containing IMSI on success
+     */
+    void getIMSIForApp(String aid, Message result);
+
+    /**
+     *  returned message
+     *  retMsg.obj = AsyncResult ar
+     *  ar.exception carries exception on failure
+     *  ar.userObject contains the orignal value of result.obj
      *  ar.result is String containing IMEI on success
      */
     void getIMEI(Message result);
@@ -1055,6 +1059,14 @@
             String data, String pin2, Message response);
 
     /**
+     * parameters equivalent to 27.007 AT+CRSM command
+     * response.obj will be an AsyncResult
+     * response.obj.userObj will be a IccIoResult on success
+     */
+    void iccIOForApp (int command, int fileid, String path, int p1, int p2, int p3,
+            String data, String pin2, String aid, Message response);
+
+    /**
      * (AsyncResult)response.obj).result is an int[] with element [0] set to
      * 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned".
      *
@@ -1559,4 +1571,9 @@
      * @param response a callback message with the String response in the obj field
      */
     public void requestIsimAuthentication(String nonce, Message response);
+
+    /**
+     * Notifiy that we are testing an emergency call
+     */
+    public void testingEmergencyCall();
 }
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 1336818..d0e304f 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -328,8 +328,11 @@
         String reason = null;
 
         if (dp.onCompletedMsg != null) {
+            // Get ApnContext, but only valid on GSM devices this is a string on CDMA devices.
             Message msg = dp.onCompletedMsg;
-            alreadySent = (ApnContext)msg.obj;
+            if (msg.obj instanceof ApnContext) {
+                alreadySent = (ApnContext)msg.obj;
+            }
             reason = dp.reason;
             if (VDBG) {
                 log(String.format("msg=%s msg.obj=%s", msg.toString(),
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 664a091..5d76484 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -225,7 +225,8 @@
     //       having to have different values for GSM and
     //       CDMA. If so we can then remove the need for
     //       getActionIntentReconnectAlarm.
-    protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
+    protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON =
+        "reconnect_alarm_extra_reason";
 
     // Used for debugging. Send the INTENT with an optional counter value with the number
     // of times the setup is to fail before succeeding. If the counter isn't passed the
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index f4308a0..a9ef762 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -48,7 +48,7 @@
     protected String mLogTag;
     protected boolean mDbg;
 
-    private IccCardStatus mIccCardStatus = null;
+    protected IccCardStatus mIccCardStatus = null;
     protected State mState = null;
     private final Object mStateMonitor = new Object();
 
@@ -911,4 +911,24 @@
     private void log(String msg) {
         Log.d(mLogTag, "[IccCard] " + msg);
     }
+
+    protected abstract int getCurrentApplicationIndex();
+
+    public String getAid() {
+        String aid = "";
+        int appIndex = getCurrentApplicationIndex();
+
+        if (appIndex >= 0 && appIndex < IccCardStatus.CARD_MAX_APPS) {
+            IccCardApplication app = mIccCardStatus.getApplication(appIndex);
+            if (app != null) {
+                aid = app.aid;
+            } else {
+                Log.e(mLogTag, "[IccCard] getAid: no current application index=" + appIndex);
+            }
+        } else {
+            Log.e(mLogTag, "[IccCard] getAid: Invalid Subscription Application index=" + appIndex);
+        }
+
+        return aid;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java
index c751a21..a3bdd76 100644
--- a/telephony/java/com/android/internal/telephony/IccCardStatus.java
+++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java
@@ -24,7 +24,7 @@
  * {@hide}
  */
 public class IccCardStatus {
-    static final int CARD_MAX_APPS = 8;
+    public static final int CARD_MAX_APPS = 8;
 
     public enum CardState {
         CARDSTATE_ABSENT,
diff --git a/telephony/java/com/android/internal/telephony/IccFileHandler.java b/telephony/java/com/android/internal/telephony/IccFileHandler.java
index 93b9b79..380bfd1 100644
--- a/telephony/java/com/android/internal/telephony/IccFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/IccFileHandler.java
@@ -145,8 +145,9 @@
             = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
                         new LoadLinearFixedContext(fileid, recordNum, onLoaded));
 
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
-                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null,
+                        phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -164,9 +165,10 @@
                         onLoaded));
 
         // TODO(): Verify when path changes are done.
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img",
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img",
                 recordNum, READ_RECORD_MODE_ABSOLUTE,
-                GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response);
+                GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null,
+                phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -182,8 +184,9 @@
         Message response
                 = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE,
                         new LoadLinearFixedContext(fileid, onLoaded));
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
-                    0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+                    0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, phone.getIccCard().getAid(),
+                    response);
     }
 
     /**
@@ -199,8 +202,9 @@
         Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
                         new LoadLinearFixedContext(fileid,onLoaded));
 
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
-                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null,
+                        phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -217,8 +221,9 @@
         Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
                         fileid, 0, onLoaded);
 
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
-                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+                        0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null,
+                        phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -236,8 +241,8 @@
         Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
                 onLoaded);
 
-        phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
-                length, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
+                length, null, null, phone.getIccCard().getAid(), response);
     }
 
     /**
@@ -251,9 +256,10 @@
      */
     public void updateEFLinearFixed(int fileid, int recordNum, byte[] data,
             String pin2, Message onComplete) {
-        phone.mCM.iccIO(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid),
+        phone.mCM.iccIOForApp(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid),
                         recordNum, READ_RECORD_MODE_ABSOLUTE, data.length,
-                        IccUtils.bytesToHexString(data), pin2, onComplete);
+                        IccUtils.bytesToHexString(data), pin2,
+                        phone.getIccCard().getAid(), onComplete);
     }
 
     /**
@@ -262,9 +268,10 @@
      * @param data must be exactly as long as the EF
      */
     public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {
-        phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
+        phone.mCM.iccIOForApp(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
                         0, 0, data.length,
-                        IccUtils.bytesToHexString(data), null, onComplete);
+                        IccUtils.bytesToHexString(data), null,
+                        phone.getIccCard().getAid(), onComplete);
     }
 
 
@@ -395,10 +402,11 @@
                      lc.results = new ArrayList<byte[]>(lc.countRecords);
                  }
 
-                 phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
+                 phone.mCM.iccIOForApp(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
                          lc.recordNum,
                          READ_RECORD_MODE_ABSOLUTE,
                          lc.recordSize, null, null,
+                         phone.getIccCard().getAid(),
                          obtainMessage(EVENT_READ_RECORD_DONE, lc));
                  break;
             case EVENT_GET_BINARY_SIZE_DONE:
@@ -433,8 +441,9 @@
                 size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
                        + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
 
-                phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
+                phone.mCM.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
                                 0, 0, size, null, null,
+                                phone.getIccCard().getAid(),
                                 obtainMessage(EVENT_READ_BINARY_DONE,
                                               fileid, 0, response));
             break;
@@ -468,10 +477,11 @@
                     if (lc.recordNum > lc.countRecords) {
                         sendResult(response, lc.results, null);
                     } else {
-                        phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
+                        phone.mCM.iccIOForApp(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
                                     lc.recordNum,
                                     READ_RECORD_MODE_ABSOLUTE,
                                     lc.recordSize, null, null,
+                                    phone.getIccCard().getAid(),
                                     obtainMessage(EVENT_READ_RECORD_DONE, lc));
                     }
                 }
diff --git a/telephony/java/com/android/internal/telephony/IccRefreshResponse.java b/telephony/java/com/android/internal/telephony/IccRefreshResponse.java
new file mode 100644
index 0000000..6806703
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccRefreshResponse.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+/**
+ * See also RIL_SimRefresh in include/telephony/ril.h
+ *
+ * {@hide}
+ */
+
+public class IccRefreshResponse {
+
+    public static final int REFRESH_RESULT_FILE_UPDATE = 0; /* Single file was updated */
+    public static final int REFRESH_RESULT_INIT = 1;        /* The Icc has been initialized */
+    public static final int REFRESH_RESULT_RESET = 2;       /* The Icc was reset */
+
+    public int             refreshResult;      /* Sim Refresh result */
+    public int             efId;               /* EFID */
+    public String          aid;                /* null terminated string, e.g.,
+                                                  from 0xA0, 0x00 -> 0x41,
+                                                  0x30, 0x30, 0x30 */
+                                               /* Example: a0000000871002f310ffff89080000ff */
+
+    @Override
+    public String toString() {
+        return "{" + refreshResult + ", " + aid +", " + efId + "}";
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 718a4fd..5afc1f3 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -52,6 +52,7 @@
 import com.android.internal.telephony.gsm.SuppServiceNotification;
 import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
 import com.android.internal.telephony.cdma.CdmaInformationRecords;
+import com.android.internal.telephony.IccRefreshResponse;
 
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
@@ -59,6 +60,7 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * {@hide}
@@ -231,6 +233,9 @@
 
     Object     mLastNITZTimeInfo;
 
+    // When we are testing emergency calls
+    AtomicBoolean mTestingEmergencyCall = new AtomicBoolean(false);
+
     //***** Events
 
     static final int EVENT_SEND                 = 1;
@@ -879,9 +884,19 @@
 
     public void
     getIMSI(Message result) {
+        getIMSIForApp(null, result);
+    }
+
+    public void
+    getIMSIForApp(String aid, Message result) {
         RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+        rr.mp.writeInt(1);
+        rr.mp.writeString(aid);
+
+        if (RILJ_LOGD) riljLog(rr.serialString() +
+                              "> getIMSI: " + requestToString(rr.mRequest)
+                              + " aid: " + aid);
 
         send(rr);
     }
@@ -1434,6 +1449,11 @@
     public void
     iccIO (int command, int fileid, String path, int p1, int p2, int p3,
             String data, String pin2, Message result) {
+        iccIOForApp(command, fileid, path, p1, p2, p3, data, pin2, null, result);
+    }
+    public void
+    iccIOForApp (int command, int fileid, String path, int p1, int p2, int p3,
+            String data, String pin2, String aid, Message result) {
         //Note: This RIL request has not been renamed to ICC,
         //       but this request is also valid for SIM and RUIM
         RILRequest rr
@@ -1447,12 +1467,15 @@
         rr.mp.writeInt(p3);
         rr.mp.writeString(data);
         rr.mp.writeString(pin2);
+        rr.mp.writeString(aid);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: " + requestToString(rr.mRequest)
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: "
+                + requestToString(rr.mRequest)
                 + " 0x" + Integer.toHexString(command)
                 + " 0x" + Integer.toHexString(fileid) + " "
                 + " path: " + path + ","
-                + p1 + "," + p2 + "," + p3);
+                + p1 + "," + p2 + "," + p3
+                + " aid: " + aid);
 
         send(rr);
     }
@@ -2194,7 +2217,16 @@
             case RIL_REQUEST_GET_IMSI: ret =  responseString(p); break;
             case RIL_REQUEST_HANGUP: ret =  responseVoid(p); break;
             case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: ret =  responseVoid(p); break;
-            case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: ret =  responseVoid(p); break;
+            case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: {
+                if (mTestingEmergencyCall.getAndSet(false)) {
+                    if (mEmergencyCallbackModeRegistrant != null) {
+                        riljLog("testing emergency call, notify ECM Registrants");
+                        mEmergencyCallbackModeRegistrant.notifyRegistrant();
+                    }
+                }
+                ret =  responseVoid(p);
+                break;
+            }
             case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: ret =  responseVoid(p); break;
             case RIL_REQUEST_CONFERENCE: ret =  responseVoid(p); break;
             case RIL_REQUEST_UDUB: ret =  responseVoid(p); break;
@@ -2419,7 +2451,7 @@
             case RIL_UNSOL_STK_EVENT_NOTIFY: ret = responseString(p); break;
             case RIL_UNSOL_STK_CALL_SETUP: ret = responseInts(p); break;
             case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ret =  responseVoid(p); break;
-            case RIL_UNSOL_SIM_REFRESH: ret =  responseInts(p); break;
+            case RIL_UNSOL_SIM_REFRESH: ret =  responseSimRefresh(p); break;
             case RIL_UNSOL_CALL_RING: ret =  responseCallRing(p); break;
             case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break;
             case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:  ret =  responseVoid(p); break;
@@ -2976,6 +3008,16 @@
     }
 
     private Object
+    responseSimRefresh(Parcel p) {
+        IccRefreshResponse response = new IccRefreshResponse();
+
+        response.refreshResult = p.readInt();
+        response.efId   = p.readInt();
+        response.aid = p.readString();
+        return response;
+    }
+
+    private Object
     responseCallList(Parcel p) {
         int num;
         int voiceSettings;
@@ -2985,6 +3027,11 @@
         num = p.readInt();
         response = new ArrayList<DriverCall>(num);
 
+        if (RILJ_LOGV) {
+            riljLog("responseCallList: num=" + num +
+                    " mEmergencyCallbackModeRegistrant=" + mEmergencyCallbackModeRegistrant +
+                    " mTestingEmergencyCall=" + mTestingEmergencyCall.get());
+        }
         for (int i = 0 ; i < num ; i++) {
             dc = new DriverCall();
 
@@ -3036,6 +3083,14 @@
 
         Collections.sort(response);
 
+        if ((num == 0) && mTestingEmergencyCall.getAndSet(false)) {
+            if (mEmergencyCallbackModeRegistrant != null) {
+                riljLog("responseCallList: call ended, testing emergency call," +
+                            " notify ECM Registrants");
+                mEmergencyCallbackModeRegistrant.notifyRegistrant();
+            }
+        }
+
         return response;
     }
 
@@ -3762,4 +3817,13 @@
 
         send(rr);
     }
+
+    /* (non-Javadoc)
+     * @see com.android.internal.telephony.BaseCommands#testingEmergencyCall()
+     */
+    @Override
+    public void testingEmergencyCall() {
+        if (RILJ_LOGD) riljLog("testingEmergencyCall");
+        mTestingEmergencyCall.set(true);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 83efc51..f918dce 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -210,7 +210,8 @@
             return dialThreeWay(dialString);
         }
 
-        pendingMO = new CdmaConnection(phone.getContext(), dialString, this, foregroundCall);
+        pendingMO = new CdmaConnection(phone.getContext(), checkForTestEmergencyNumber(dialString),
+                this, foregroundCall);
         hangupPendingMO = false;
 
         if (pendingMO.address == null || pendingMO.address.length() == 0
@@ -259,7 +260,7 @@
 
             // Attach the new connection to foregroundCall
             pendingMO = new CdmaConnection(phone.getContext(),
-                                dialString, this, foregroundCall);
+                                checkForTestEmergencyNumber(dialString), this, foregroundCall);
             cm.sendCDMAFeatureCode(pendingMO.address,
                 obtainMessage(EVENT_THREE_WAY_DIAL_L2_RESULT_CDMA));
             return pendingMO;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 6b73cc5..7da23d0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -124,7 +124,9 @@
 
     @Override
     protected void setSignalStrengthDefaultValues() {
-        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, false);
+        // TODO Make a constructor only has boolean gsm as parameter
+        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1,
+                -1, -1, -1, SignalStrength.INVALID_SNR, -1, false);
     }
 
     @Override
@@ -429,8 +431,13 @@
             setSignalStrengthDefaultValues();
         } else {
             int[] ints = (int[])ar.result;
-            int lteCqi = 99, lteRsrp = -1;
-            int lteRssi = 99;
+
+            int lteRssi = -1;
+            int lteRsrp = -1;
+            int lteRsrq = -1;
+            int lteRssnr = SignalStrength.INVALID_SNR;
+            int lteCqi = -1;
+
             int offset = 2;
             int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
             int cdmaEcio = (ints[offset + 1] > 0) ? -ints[offset + 1] : -160;
@@ -438,10 +445,13 @@
             int evdoEcio = (ints[offset + 3] > 0) ? -ints[offset + 3] : -1;
             int evdoSnr = ((ints[offset + 4] > 0) && (ints[offset + 4] <= 8)) ? ints[offset + 4]
                     : -1;
+
             if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) {
-                lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99;
-                lteRsrp = (ints[offset + 6] < 0) ? ints[offset + 6] : -1;
-                lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 7] : 99;
+                lteRssi = ints[offset+5];
+                lteRsrp = ints[offset+6];
+                lteRsrq = ints[offset+7];
+                lteRssnr = ints[offset+8];
+                lteCqi = ints[offset+9];
             }
 
             if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) {
@@ -449,7 +459,7 @@
                         evdoSnr, false);
             } else {
                 mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
-                        evdoSnr, lteRssi, lteRsrp, -1, -1, lteCqi, true);
+                        evdoSnr, lteRssi, lteRsrp, lteRsrq, lteRssnr, lteCqi, true);
             }
         }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
index b57af0e..8375fd0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
@@ -55,8 +55,8 @@
         if (fileid == EF_CSIM_EPRL) {
             // Entire PRL could be huge. We are only interested in
             // the first 4 bytes of the record.
-            phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
-                            0, 0, 4, null, null,
+            phone.mCM.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
+                            0, 0, 4, null, null, phone.getIccCard().getAid(),
                             obtainMessage(EVENT_READ_BINARY_DONE,
                                           fileid, 0, onLoaded));
         } else {
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
index 02eb86d..674fada 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
@@ -44,5 +44,13 @@
     public String getServiceProviderName () {
         return mPhone.mIccRecords.getServiceProviderName();
     }
+
+    @Override
+    protected int getCurrentApplicationIndex() {
+        if (mIccCardStatus == null) {
+            return -1;
+        }
+        return mIccCardStatus.getCdmaSubscriptionAppIndex();
+    }
  }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
index 3e2a29b..375cc07 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
@@ -57,8 +57,9 @@
         Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
                 onLoaded);
 
-        phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, "img", 0, 0,
-                GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response);
+        phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, "img", 0, 0,
+                GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null,
+                phone.getIccCard().getAid(), response);
     }
 
     @Override
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index b057e46..17a200e 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -29,6 +29,7 @@
 import com.android.internal.telephony.AdnRecordCache;
 import com.android.internal.telephony.AdnRecordLoader;
 import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.IccRefreshResponse;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.cdma.RuimCard;
 import com.android.internal.telephony.MccTable;
@@ -300,7 +301,7 @@
                 isRecordLoadResponse = false;
                 ar = (AsyncResult)msg.obj;
                 if (ar.exception == null) {
-                    handleRuimRefresh((int[])(ar.result));
+                    handleRuimRefresh((IccRefreshResponse)ar.result);
                 }
                 break;
 
@@ -409,24 +410,30 @@
         ((CDMAPhone) phone).notifyMessageWaitingIndicator();
     }
 
-    private void handleRuimRefresh(int[] result) {
-        if (result == null || result.length == 0) {
-            if (DBG) log("handleRuimRefresh without input");
+    private void handleRuimRefresh(IccRefreshResponse refreshResponse) {
+        if (refreshResponse == null) {
+            if (DBG) log("handleRuimRefresh received without input");
             return;
         }
 
-        switch ((result[0])) {
-            case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
+        if (refreshResponse.aid != null &&
+                !refreshResponse.aid.equals(phone.getIccCard().getAid())) {
+            // This is for different app. Ignore.
+            return;
+        }
+
+        switch (refreshResponse.refreshResult) {
+            case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
                 if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED");
                 adnCache.reset();
                 fetchRuimRecords();
                 break;
-            case CommandsInterface.SIM_REFRESH_INIT:
+            case IccRefreshResponse.REFRESH_RESULT_INIT:
                 if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT");
                 // need to reload all files (that we care about)
                 fetchRuimRecords();
                 break;
-            case CommandsInterface.SIM_REFRESH_RESET:
+            case IccRefreshResponse.REFRESH_RESULT_RESET:
                 if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET");
                 phone.mCM.setRadioPower(false, null);
                 /* Note: no need to call setRadioPower(true).  Assuming the desired
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index 06f310c..425afe6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -198,7 +198,8 @@
             throw new CallStateException("cannot dial in current state");
         }
 
-        pendingMO = new GsmConnection(phone.getContext(), dialString, this, foregroundCall);
+        pendingMO = new GsmConnection(phone.getContext(), checkForTestEmergencyNumber(dialString),
+                this, foregroundCall);
         hangupPendingMO = false;
 
         if (pendingMO.address == null || pendingMO.address.length() == 0
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 8f04dba..66e9487 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -131,7 +131,7 @@
 
     private static final String INTENT_RECONNECT_ALARM =
         "com.android.internal.telephony.gprs-reconnect";
-    private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "type";
+    private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type";
 
     private static final String INTENT_DATA_STALL_ALARM =
         "com.android.internal.telephony.gprs-data-stall";
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 92e16ce..0ebeabe 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -675,7 +675,9 @@
     }
 
     private void setSignalStrengthDefaultValues() {
-        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, true);
+        // TODO Make a constructor only has boolean gsm as parameter
+        mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1,
+                -1, -1, -1, SignalStrength.INVALID_SNR, -1, true);
     }
 
     /**
@@ -1013,7 +1015,7 @@
         int lteSignalStrength = -1;
         int lteRsrp = -1;
         int lteRsrq = -1;
-        int lteRssnr = -1;
+        int lteRssnr = SignalStrength.INVALID_SNR;
         int lteCqi = -1;
 
         if (ar.exception != null) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 7c423c7..de8401e 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -39,6 +39,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
 import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.IccRefreshResponse;
 
 import java.util.ArrayList;
 
@@ -1049,7 +1050,7 @@
                 ar = (AsyncResult)msg.obj;
                 if (DBG) log("Sim REFRESH with exception: " + ar.exception);
                 if (ar.exception == null) {
-                    handleSimRefresh((int[])(ar.result));
+                    handleSimRefresh((IccRefreshResponse)ar.result);
                 }
                 break;
             case EVENT_GET_CFIS_DONE:
@@ -1130,27 +1131,31 @@
         }
     }
 
-    private void handleSimRefresh(int[] result) {
-        if (result == null || result.length == 0) {
-	    if (DBG) log("handleSimRefresh without input");
+    private void handleSimRefresh(IccRefreshResponse refreshResponse){
+        if (refreshResponse == null) {
+            if (DBG) log("handleSimRefresh received without input");
             return;
         }
 
-        switch ((result[0])) {
-            case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
- 		if (DBG) log("handleSimRefresh with SIM_REFRESH_FILE_UPDATED");
-                // result[1] contains the EFID of the updated file.
-                int efid = result[1];
-                handleFileUpdate(efid);
+        if (refreshResponse.aid != null &&
+                !refreshResponse.aid.equals(phone.getIccCard().getAid())) {
+            // This is for different app. Ignore.
+            return;
+        }
+
+        switch (refreshResponse.refreshResult) {
+            case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
+                if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED");
+                handleFileUpdate(refreshResponse.efId);
                 break;
-            case CommandsInterface.SIM_REFRESH_INIT:
-		if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
+            case IccRefreshResponse.REFRESH_RESULT_INIT:
+                if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
                 // need to reload all files (that we care about)
                 adnCache.reset();
                 fetchSimRecords();
                 break;
-            case CommandsInterface.SIM_REFRESH_RESET:
-		if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
+            case IccRefreshResponse.REFRESH_RESULT_RESET:
+                if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
                 phone.mCM.setRadioPower(false, null);
                 /* Note: no need to call setRadioPower(true).  Assuming the desired
                 * radio power state is still ON (as tracked by ServiceStateTracker),
@@ -1162,7 +1167,7 @@
                 break;
             default:
                 // unknown refresh operation
-		if (DBG) log("handleSimRefresh with unknown operation");
+                if (DBG) log("handleSimRefresh with unknown operation");
                 break;
         }
     }
@@ -1304,7 +1309,7 @@
 
         logv("fetchSimRecords " + recordsToLoad);
 
-        phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
+        phone.mCM.getIMSIForApp(phone.getIccCard().getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
         recordsToLoad++;
 
         iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index e34e10a..0e68e07 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -39,4 +39,11 @@
         return mPhone.mIccRecords.getServiceProviderName();
     }
 
+    @Override
+    protected int getCurrentApplicationIndex() {
+        if (mIccCardStatus == null) {
+            return -1;
+        }
+        return mIccCardStatus.getGsmUmtsSubscriptionAppIndex();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
index 9201984..99f4e0f 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -84,6 +84,9 @@
     public void getIMSI(Message result) {
     }
 
+    public void getIMSIForApp(String aid, Message result) {
+    }
+
     public void getIMEI(Message result) {
     }
 
@@ -213,6 +216,9 @@
     public void iccIO (int command, int fileid, String path, int p1, int p2,
             int p3, String data, String pin2, Message result) {
     }
+    public void iccIOForApp (int command, int fileid, String path, int p1, int p2,
+            int p3, String data, String pin2, String aid, Message result) {
+    }
 
     public void getCLIR(Message result) {
     }
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index 60d9d24..4f61509 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -504,6 +504,9 @@
         resultSuccess(result, null);
     }
 
+    public void getIMSI(Message result) {
+        getIMSIForApp(null, result);
+    }
     /**
      *  returned message
      *  retMsg.obj = AsyncResult ar
@@ -511,7 +514,7 @@
      *  ar.userObject contains the original value of result.obj
      *  ar.result is String containing IMSI on success
      */
-    public void getIMSI(Message result) {
+    public void getIMSIForApp(String aid, Message result) {
         resultSuccess(result, "012345678901234");
     }
 
@@ -1042,13 +1045,18 @@
         unimplemented(result);
     }
 
+    public void iccIO(int command, int fileid, String path, int p1, int p2, int p3, String data,
+            String pin2, Message response) {
+        iccIOForApp(command, fileid, path, p1, p2, p3, data,pin2, null, response);
+    }
+
     /**
      * parameters equivalent to 27.007 AT+CRSM command
      * response.obj will be an AsyncResult
      * response.obj.userObj will be a SimIoResult on success
      */
-    public void iccIO (int command, int fileid, String path, int p1, int p2,
-                       int p3, String data, String pin2, Message result) {
+    public void iccIOForApp (int command, int fileid, String path, int p1, int p2,
+                       int p3, String data, String pin2, String aid, Message result) {
         unimplemented(result);
     }
 
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index a385f55..9d9680d 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -511,8 +511,12 @@
     @SmallTest
     public void testFormatNumber() {
         assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "US"));
-        assertEquals("123-4567", PhoneNumberUtils.formatNumber("1234567", "US"));
-        assertEquals("(800) 466-4114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
+        assertEquals("223-4567", PhoneNumberUtils.formatNumber("2234567", "US"));
+        assertEquals("011 86 10 8888 0000",
+                     PhoneNumberUtils.formatNumber("011861088880000", "US"));
+        assertEquals("010 8888 0000", PhoneNumberUtils.formatNumber("01088880000", "CN"));
+        // formatNumber doesn't format alpha numbers, but keep them as they are.
+        assertEquals("800-GOOG-114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
     }
 
     @SmallTest
@@ -541,6 +545,16 @@
         // Using the phoneNumberE164's country code
         assertEquals("(650) 291-0000",
                 PhoneNumberUtils.formatNumber("6502910000", "+16502910000", "CN"));
+        // Using the default country code for a phone number containing the IDD
+        assertEquals("011 86 10 8888 0000",
+                PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "US"));
+        assertEquals("00 86 10 8888 0000",
+                PhoneNumberUtils.formatNumber("00861088880000", "+861088880000", "GB"));
+        assertEquals("+86 10 8888 0000",
+                PhoneNumberUtils.formatNumber("+861088880000", "+861088880000", "GB"));
+        // Wrong default country, so no formatting is done
+        assertEquals("011861088880000",
+                PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "GB"));
         // The phoneNumberE164 is null
         assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("6502910000", null, "US"));
         // The given number has a country code.
@@ -552,7 +566,11 @@
         // An invalid Polish number should be left as it is. Note Poland doesn't use '0' as a
         // national prefix; therefore, the leading '0' makes the number invalid.
         assertEquals("0506128687", PhoneNumberUtils.formatNumber("0506128687", null, "PL"));
+        // Wrong default country, so no formatting is done
+        assertEquals("011861088880000",
+                PhoneNumberUtils.formatNumber("011861088880000", "", "GB"));
     }
+
     @SmallTest
     public void testIsEmergencyNumber() {
         // There are two parallel sets of tests here: one for the
@@ -592,9 +610,12 @@
         // addressing that, they are also classified as "potential" emergency numbers in the US.
         assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "US"));
         assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("11212345", "US"));
+
         // A valid mobile phone number from Singapore shouldn't be classified as an emergency number
         // in Singapore, as 911 is not an emergency number there.
-        assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91121234", "SG"));
+        // This test fails on devices that have ecclist property preloaded with 911.
+        // assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91121234", "SG"));
+
         // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number
         // in Brazil, as 112 is not an emergency number there.
         assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("1121234567", "BR"));
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
index d2e573c..6f0175e 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
@@ -64,7 +64,7 @@
         assertEquals(result1, number.toString());
         assertEquals(result1.length(), Selection.getSelectionEnd(number));
         // Remove last 5 chars
-        final String result2 = "(650) 123";
+        final String result2 = "650-123";
         textWatcher.beforeTextChanged(number, number.length() - 4, 4, 0);
         number.delete(number.length() - 5, number.length());
         Selection.setSelection(number, number.length());
@@ -75,26 +75,26 @@
     }
 
     public void testInsertChars() {
-        final String init = "(650) 23";
-        final String expected1 = "(650) 123";
+        final String init = "650-23";
+        final String expected1 = "650-123";
         TextWatcher textWatcher = getTextWatcher();
 
         // Insert one char
         SpannableStringBuilder number = new SpannableStringBuilder(init);
-        textWatcher.beforeTextChanged(number, 4, 0, 1);
-        number.insert(4, "1"); // (6501) 23
-        Selection.setSelection(number, 5); // make the cursor at right of 1
-        textWatcher.onTextChanged(number, 4, 0, 1);
+        textWatcher.beforeTextChanged(number, 3, 0, 1);
+        number.insert(3, "1"); // 6501-23
+        Selection.setSelection(number, 4); // make the cursor at right of 1
+        textWatcher.onTextChanged(number, 3, 0, 1);
         textWatcher.afterTextChanged(number);
         assertEquals(expected1, number.toString());
         // the cursor should still at the right of '1'
-        assertEquals(7, Selection.getSelectionEnd(number));
+        assertEquals(5, Selection.getSelectionEnd(number));
 
         // Insert multiple chars
         final String expected2 = "(650) 145-6723";
-        textWatcher.beforeTextChanged(number, 7, 0, 4);
-        number.insert(7, "4567"); // change to (650) 1456723
-        Selection.setSelection(number, 11); // the cursor is at the right of '7'.
+        textWatcher.beforeTextChanged(number, 5, 0, 4);
+        number.insert(5, "4567"); // change to 650-1456723
+        Selection.setSelection(number, 9); // the cursor is at the right of '7'.
         textWatcher.onTextChanged(number, 7, 0, 4);
         textWatcher.afterTextChanged(number);
         assertEquals(expected2, number.toString());
@@ -168,7 +168,7 @@
         textWatcher.onTextChanged(number, 0, len, 0);
         textWatcher.afterTextChanged(number);
 
-        final String expected2 = "(650) 123-4";
+        final String expected2 = "650-1234";
         number = new SpannableStringBuilder(init);
         textWatcher.beforeTextChanged(number, 9, 0, 1);
         number.insert(9, "4"); // (650) 1234
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
index b385cee..ea6836d 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
@@ -612,4 +612,13 @@
     @Override
     public void getVoiceRadioTechnology(Message response) {
     }
+
+    @Override
+    public void getIMSIForApp(String aid, Message result) {
+    }
+
+    @Override
+    public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3,
+            String data, String pin2, String aid, Message response) {
+    }
 }
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index e0ce322..a8c388e 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -21,6 +21,7 @@
 import android.content.ContentProviderResult;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.ICancellationSignal;
 import android.content.IContentProvider;
 import android.content.OperationApplicationException;
 import android.content.pm.PathPermission;
@@ -92,7 +93,7 @@
 
         @Override
         public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
-                String sortOrder) throws RemoteException {
+                String sortOrder, ICancellationSignal cancellationSignal) throws RemoteException {
             return MockContentProvider.this.query(url, projection, selection,
                     selectionArgs, sortOrder);
         }
@@ -124,6 +125,11 @@
                 throws RemoteException, FileNotFoundException {
             return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts);
         }
+
+        @Override
+        public ICancellationSignal createCancellationSignal() throws RemoteException {
+            return null;
+        }
     }
     private final InversionIContentProvider mIContentProvider = new InversionIContentProvider();
 
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 0b4fc51..674c0b7 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -333,6 +333,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void unbindService(ServiceConnection conn) {
         throw new UnsupportedOperationException();
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index b7733a4..1aa0448 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -21,6 +21,7 @@
 import android.content.ContentValues;
 import android.content.EntityIterator;
 import android.content.IContentProvider;
+import android.content.ICancellationSignal;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
@@ -72,7 +73,7 @@
     }
 
     public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
+            String sortOrder, ICancellationSignal cancellationSignal) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
@@ -103,4 +104,9 @@
             throws RemoteException, FileNotFoundException {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
+
+    @Override
+    public ICancellationSignal createCancellationSignal() throws RemoteException {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
 }
diff --git a/tests/ActivityTests/res/anim/slow_enter.xml b/tests/ActivityTests/res/anim/slow_enter.xml
new file mode 100644
index 0000000..0309643
--- /dev/null
+++ b/tests/ActivityTests/res/anim/slow_enter.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false" >
+    <scale android:fromXScale="0.9" android:toXScale="1.5"
+           android:fromYScale="0.9" android:toYScale="1.5"
+           android:pivotX="50%" android:pivotY="50%"
+           android:interpolator="@interpolator/slow_enter"
+           android:duration="40000" />
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+            android:interpolator="@android:interpolator/decelerate_cubic"
+            android:duration="1000" />
+</set>
diff --git a/tests/ActivityTests/res/anim/slow_exit.xml b/tests/ActivityTests/res/anim/slow_exit.xml
new file mode 100644
index 0000000..6cd3114
--- /dev/null
+++ b/tests/ActivityTests/res/anim/slow_exit.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false" >
+    <scale android:fromXScale="1.0" android:toXScale="0.9"
+            android:fromYScale="1.0" android:toYScale="0.9"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@android:interpolator/decelerate_quint"
+            android:duration="300" />
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:interpolator="@android:interpolator/decelerate_cubic"
+            android:duration="300"/>
+</set>
diff --git a/tests/ActivityTests/res/interpolator/slow_enter.xml b/tests/ActivityTests/res/interpolator/slow_enter.xml
new file mode 100644
index 0000000..ddab1aa
--- /dev/null
+++ b/tests/ActivityTests/res/interpolator/slow_enter.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:cycles="10" />
diff --git a/tests/ActivityTests/res/values/themes.xml b/tests/ActivityTests/res/values/themes.xml
new file mode 100644
index 0000000..67f5938
--- /dev/null
+++ b/tests/ActivityTests/res/values/themes.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="SlowDialog" parent="@android:style/Theme.Holo.Dialog">
+        <item name="android:windowAnimationStyle">@style/SlowDialog</item>
+    </style>
+    <style name="SlowDialog">
+        <item name="android:windowEnterAnimation">@anim/slow_enter</item>
+        <item name="android:windowExitAnimation">@anim/slow_exit</item>
+    </style>
+</resources>
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 583c13c..ae42e29 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -22,6 +22,7 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
+import android.app.AlertDialog;
 import android.app.Application;
 import android.content.ActivityNotFoundException;
 import android.os.Bundle;
@@ -35,6 +36,8 @@
 import android.widget.TextView;
 import android.widget.ScrollView;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -101,6 +104,20 @@
     }
 
     @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        menu.add("Animate!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override public boolean onMenuItemClick(MenuItem item) {
+                AlertDialog.Builder builder = new AlertDialog.Builder(ActivityTestMain.this,
+                        R.style.SlowDialog);
+                builder.setTitle("This is a title");
+                builder.show();
+                return true;
+            }
+        });
+        return true;
+    }
+
+    @Override
     protected void onStart() {
         super.onStart();
         buildUi();
diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml
index f503658..7d4d4db 100644
--- a/tests/BiDiTests/res/layout/basic.xml
+++ b/tests/BiDiTests/res/layout/basic.xml
@@ -19,6 +19,10 @@
         android:layout_width="fill_parent"
         android:layout_height="fill_parent">
 
+    <ScrollView
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent">
+
     <LinearLayout android:orientation="vertical"
                   android:layout_width="match_parent"
                   android:layout_height="match_parent">
@@ -131,4 +135,6 @@
 
     </LinearLayout>
 
+    </ScrollView>
+
 </FrameLayout>
diff --git a/tests/BiDiTests/res/layout/grid_layout_code.xml b/tests/BiDiTests/res/layout/grid_layout_code.xml
new file mode 100644
index 0000000..87a0ec0
--- /dev/null
+++ b/tests/BiDiTests/res/layout/grid_layout_code.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/grid_layout_code"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/grid_layout_locale.xml b/tests/BiDiTests/res/layout/grid_layout_locale.xml
new file mode 100644
index 0000000..4198898
--- /dev/null
+++ b/tests/BiDiTests/res/layout/grid_layout_locale.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/grid_layout_locale"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+
+    <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:useDefaultMargins="true"
+            android:alignmentMode="alignBounds"
+            android:columnOrderPreserved="false"
+            android:columnCount="4"
+            android:layoutDirection="locale">
+
+        <TextView
+                android:text="Email setup"
+                android:textSize="32dip"
+
+                android:layout_columnSpan="4"
+                android:layout_gravity="center_horizontal"/>
+
+        <TextView
+                android:text="You can configure email in just a few steps:"
+                android:textSize="16dip"
+                android:layout_columnSpan="4"
+                android:layout_gravity="left"/>
+
+        <TextView
+                android:text="Email address:"
+                android:layout_gravity="right"/>
+
+        <EditText
+                android:ems="10"/>
+
+        <TextView
+                android:text="Password:"
+                android:layout_column="0"
+                android:layout_gravity="right"/>
+
+        <EditText
+                android:ems="8"/>
+
+        <Space
+                android:layout_row="4"
+                android:layout_column="0"
+                android:layout_columnSpan="3"
+                android:layout_gravity="fill"
+                />
+
+        <Button
+                android:text="Next"
+                android:layout_row="5"
+                android:layout_column="3"/>
+
+    </GridLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/grid_layout_ltr.xml b/tests/BiDiTests/res/layout/grid_layout_ltr.xml
new file mode 100644
index 0000000..e320809
--- /dev/null
+++ b/tests/BiDiTests/res/layout/grid_layout_ltr.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/grid_layout_ltr"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+
+    <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:useDefaultMargins="true"
+            android:alignmentMode="alignBounds"
+            android:columnOrderPreserved="false"
+            android:columnCount="4"
+            android:layoutDirection="ltr">
+
+        <TextView
+                android:text="Email setup"
+                android:textSize="32dip"
+
+                android:layout_columnSpan="4"
+                android:layout_gravity="center_horizontal"/>
+
+        <TextView
+                android:text="You can configure email in just a few steps:"
+                android:textSize="16dip"
+                android:layout_columnSpan="4"
+                android:layout_gravity="left"/>
+
+        <TextView
+                android:text="Email address:"
+                android:layout_gravity="right"/>
+
+        <EditText
+                android:ems="10"/>
+
+        <TextView
+                android:text="Password:"
+                android:layout_column="0"
+                android:layout_gravity="right"/>
+
+        <EditText
+                android:ems="8"/>
+
+        <TextView
+                android:text="You can configure email in just a few steps:"
+                android:textSize="16dip"
+                android:layout_columnSpan="4"
+                android:layout_gravity="start"/>
+
+        <TextView
+                android:text="Email address:"
+                android:layout_gravity="end"/>
+
+        <EditText
+                android:ems="10"/>
+
+        <TextView
+                android:text="Password:"
+                android:layout_column="0"
+                android:layout_gravity="end"/>
+
+        <EditText
+                android:ems="8"/>
+
+        <Space
+                android:layout_row="4"
+                android:layout_column="0"
+                android:layout_columnSpan="3"
+                android:layout_gravity="fill"
+                />
+
+        <Button
+                android:text="Next"
+                android:layout_row="5"
+                android:layout_column="3"/>
+
+    </GridLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/layout/grid_layout_rtl.xml b/tests/BiDiTests/res/layout/grid_layout_rtl.xml
new file mode 100644
index 0000000..6d3aae6
--- /dev/null
+++ b/tests/BiDiTests/res/layout/grid_layout_rtl.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/grid_layout_rtl"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+
+    <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:useDefaultMargins="true"
+            android:alignmentMode="alignBounds"
+            android:columnOrderPreserved="false"
+            android:columnCount="4"
+            android:layoutDirection="rtl">
+
+        <TextView
+                android:text="Email setup"
+                android:textSize="32dip"
+
+                android:layout_columnSpan="4"
+                android:layout_gravity="center_horizontal"/>
+
+        <TextView
+                android:text="You can configure email in just a few steps:"
+                android:textSize="16dip"
+                android:layout_columnSpan="4"
+                android:layout_gravity="left"/>
+
+        <TextView
+                android:text="Email address:"
+                android:layout_gravity="right"/>
+
+        <EditText
+                android:ems="10"/>
+
+        <TextView
+                android:text="Password:"
+                android:layout_column="0"
+                android:layout_gravity="right"/>
+
+        <EditText
+                android:ems="8"/>
+
+        <TextView
+                android:text="You can configure email in just a few steps:"
+                android:textSize="16dip"
+                android:layout_columnSpan="4"
+                android:layout_gravity="end"/>
+
+        <TextView
+                android:text="Email address:"
+                android:layout_gravity="start"/>
+
+        <EditText
+                android:ems="10"/>
+
+        <TextView
+                android:text="Password:"
+                android:layout_column="0"
+                android:layout_gravity="start"/>
+
+        <EditText
+                android:ems="8"/>
+
+        <Space
+                android:layout_row="4"
+                android:layout_column="0"
+                android:layout_columnSpan="3"
+                android:layout_gravity="fill"
+                />
+
+        <Button
+                android:text="Next"
+                android:layout_row="5"
+                android:layout_column="3"/>
+
+    </GridLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index 1d4fc84..233cd0d 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -24,11 +24,11 @@
     <string name="button_before_text">Start</string>
     <string name="button_requestlayout_text">Request Layout</string>
     <string name="button_alert_dialog_text">AlertDialog</string>
-    <string name="textview_text">This is a text for a TextView</string>
-    <string name="textview_ltr_text">This is a text for a LTR TextView</string>
-    <string name="textview_rtl_text">This is a text for a RTL TextView</string>
-    <string name="textview_default_text">This is a text for a default TextView</string>
-    <string name="textview_password_default_text">This is a text for a password TextView</string>
+    <string name="textview_text">TextView</string>
+    <string name="textview_ltr_text">LTR TextView</string>
+    <string name="textview_rtl_text">RTL TextView</string>
+    <string name="textview_default_text">Default TextView</string>
+    <string name="textview_password_default_text">Password TextView</string>
     <string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
     <string name="normal_text">Normal String</string>
     <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index b45b98f..c5a1235 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -108,6 +108,12 @@
         addItem(result, "Linear RTL", BiDiTestLinearLayoutRtl.class, R.id.linear_layout_rtl);
         addItem(result, "Linear LOC", BiDiTestLinearLayoutLocale.class, R.id.linear_layout_locale);
 
+        addItem(result, "Grid LTR", BiDiTestGridLayoutLtr.class, R.id.grid_layout_ltr);
+        addItem(result, "Grid RTL", BiDiTestGridLayoutRtl.class, R.id.grid_layout_rtl);
+        addItem(result, "Grid LOC", BiDiTestGridLayoutLocale.class, R.id.grid_layout_locale);
+        addItem(result, "Grid C-LTR", BiDiTestGridLayoutCodeLtr.class, R.id.grid_layout_code);
+        addItem(result, "Grid C-RTL", BiDiTestGridLayoutCodeRtl.class, R.id.grid_layout_code);
+
         addItem(result, "Frame LTR", BiDiTestFrameLayoutLtr.class, R.id.frame_layout_ltr);
         addItem(result, "Frame RTL", BiDiTestFrameLayoutRtl.class, R.id.frame_layout_rtl);
         addItem(result, "Frame LOC", BiDiTestFrameLayoutLocale.class, R.id.frame_layout_locale);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java
new file mode 100644
index 0000000..2b5e674
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridLayout;
+import android.widget.*;
+
+import static android.text.InputType.*;
+import static android.widget.GridLayout.*;
+
+public class BiDiTestGridLayoutCodeLtr extends Fragment {
+
+    private FrameLayout currentView;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        currentView = (FrameLayout) inflater.inflate(R.layout.grid_layout_code, container, false);
+        return currentView;
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        currentView.addView(create(currentView.getContext()));
+    }
+
+    public static View create(Context context) {
+        GridLayout layout = new GridLayout(context);
+        layout.setUseDefaultMargins(true);
+        layout.setAlignmentMode(ALIGN_BOUNDS);
+        layout.setRowOrderPreserved(false);
+        layout.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+
+        Spec row1 = spec(0);
+        Spec row2 = spec(1);
+        Spec row3 = spec(2, BASELINE);
+        Spec row4 = spec(3, BASELINE);
+        Spec row5 = spec(2, 3, FILL); // allow the last two rows to overlap the middle two
+        Spec row6 = spec(5);
+        Spec row7 = spec(6);
+
+        Spec col1a = spec(0, 4, CENTER);
+        Spec col1b = spec(0, 4, LEFT);
+        Spec col1c = spec(0, RIGHT);
+        Spec col2 = spec(1, START);
+        Spec col3 = spec(2, FILL);
+        Spec col4a = spec(3);
+        Spec col4b = spec(3, FILL);
+
+        {
+            TextView c = new TextView(context);
+            c.setTextSize(32);
+            c.setText("Email setup");
+            layout.addView(c, new GridLayout.LayoutParams(row1, col1a));
+        }
+        {
+            TextView c = new TextView(context);
+            c.setTextSize(16);
+            c.setText("You can configure email in just a few steps:");
+            layout.addView(c, new GridLayout.LayoutParams(row2, col1b));
+        }
+        {
+            TextView c = new TextView(context);
+            c.setText("Email address:");
+            layout.addView(c, new GridLayout.LayoutParams(row3, col1c));
+        }
+        {
+            EditText c = new EditText(context);
+            c.setEms(10);
+            c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+            layout.addView(c, new GridLayout.LayoutParams(row3, col2));
+        }
+        {
+            TextView c = new TextView(context);
+            c.setText("Password:");
+            layout.addView(c, new GridLayout.LayoutParams(row4, col1c));
+        }
+        {
+            TextView c = new EditText(context);
+            c.setEms(8);
+            c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
+            layout.addView(c, new GridLayout.LayoutParams(row4, col2));
+        }
+        {
+            Space c = new Space(context);
+            layout.addView(c, new GridLayout.LayoutParams(row5, col3));
+        }
+        {
+            Button c = new Button(context);
+            c.setText("Manual setup");
+            layout.addView(c, new GridLayout.LayoutParams(row6, col4a));
+        }
+        {
+            Button c = new Button(context);
+            c.setText("Next");
+            layout.addView(c, new GridLayout.LayoutParams(row7, col4b));
+        }
+
+        return layout;
+    }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java
new file mode 100644
index 0000000..3a03c6c
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridLayout;
+import android.widget.*;
+
+import static android.text.InputType.*;
+import static android.widget.GridLayout.*;
+
+public class BiDiTestGridLayoutCodeRtl extends Fragment {
+
+    private FrameLayout currentView;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        currentView = (FrameLayout) inflater.inflate(R.layout.grid_layout_code, container, false);
+        return currentView;
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        currentView.addView(create(currentView.getContext()));
+    }
+
+    public static View create(Context context) {
+        GridLayout layout = new GridLayout(context);
+        layout.setUseDefaultMargins(true);
+        layout.setAlignmentMode(ALIGN_BOUNDS);
+        layout.setRowOrderPreserved(false);
+        layout.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+
+        Spec row1 = spec(0);
+        Spec row2 = spec(1);
+        Spec row3 = spec(2, BASELINE);
+        Spec row4 = spec(3, BASELINE);
+        Spec row5 = spec(2, 3, FILL); // allow the last two rows to overlap the middle two
+        Spec row6 = spec(5);
+        Spec row7 = spec(6);
+
+        Spec col1a = spec(0, 4, CENTER);
+        Spec col1b = spec(0, 4, LEFT);
+        Spec col1c = spec(0, RIGHT);
+        Spec col2 = spec(1, START);
+        Spec col3 = spec(2, FILL);
+        Spec col4a = spec(3);
+        Spec col4b = spec(3, FILL);
+
+        {
+            TextView c = new TextView(context);
+            c.setTextSize(32);
+            c.setText("Email setup");
+            layout.addView(c, new GridLayout.LayoutParams(row1, col1a));
+        }
+        {
+            TextView c = new TextView(context);
+            c.setTextSize(16);
+            c.setText("You can configure email in just a few steps:");
+            layout.addView(c, new GridLayout.LayoutParams(row2, col1b));
+        }
+        {
+            TextView c = new TextView(context);
+            c.setText("Email address:");
+            layout.addView(c, new GridLayout.LayoutParams(row3, col1c));
+        }
+        {
+            EditText c = new EditText(context);
+            c.setEms(10);
+            c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+            layout.addView(c, new GridLayout.LayoutParams(row3, col2));
+        }
+        {
+            TextView c = new TextView(context);
+            c.setText("Password:");
+            layout.addView(c, new GridLayout.LayoutParams(row4, col1c));
+        }
+        {
+            TextView c = new EditText(context);
+            c.setEms(8);
+            c.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
+            layout.addView(c, new GridLayout.LayoutParams(row4, col2));
+        }
+        {
+            Space c = new Space(context);
+            layout.addView(c, new GridLayout.LayoutParams(row5, col3));
+        }
+        {
+            Button c = new Button(context);
+            c.setText("Manual setup");
+            layout.addView(c, new GridLayout.LayoutParams(row6, col4a));
+        }
+        {
+            Button c = new Button(context);
+            c.setText("Next");
+            layout.addView(c, new GridLayout.LayoutParams(row7, col4b));
+        }
+
+        return layout;
+    }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutLocale.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutLocale.java
new file mode 100644
index 0000000..16e61ad
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutLocale.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class BiDiTestGridLayoutLocale extends Fragment {
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.grid_layout_locale, container, false);
+    }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutLtr.java
new file mode 100644
index 0000000..df6c9fe
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutLtr.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class BiDiTestGridLayoutLtr extends Fragment {
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.grid_layout_ltr, container, false);
+    }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutRtl.java
new file mode 100644
index 0000000..8bed113
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutRtl.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class BiDiTestGridLayoutRtl extends Fragment {
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.grid_layout_rtl, container, false);
+    }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index c0ba8cf..83c9c3d 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -22,12 +22,12 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.Intent;
 import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Bitmap.CompressFormat;
 import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
 import android.net.http.SslError;
 import android.os.Bundle;
 import android.os.Environment;
@@ -36,7 +36,6 @@
 import android.util.Log;
 import android.view.ViewGroup;
 import android.view.Window;
-import android.webkit.CookieManager;
 import android.webkit.ConsoleMessage;
 import android.webkit.CookieManager;
 import android.webkit.GeolocationPermissions;
@@ -904,9 +903,7 @@
         settings.setWorkersEnabled(false);
         settings.setXSSAuditorEnabled(false);
         settings.setPageCacheCapacity(0);
-        // this enables cpu upload path (as opposed to gpu upload path)
-        // and it's only meant to be a temporary workaround!
-        settings.setProperty("enable_cpu_upload_path", "true");
+        settings.setProperty("use_minimal_memory", "false");
     }
 
     private WebView mWebView;
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 5bbcce3..3904c21 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -30,6 +30,8 @@
         android:label="HwUi"
         android:hardwareAccelerated="true">
 
+        <meta-data android:name="android.graphics.renderThread" android:value="true" />
+
         <activity
                 android:name="PaintDrawFilterActivity"
                 android:label="_DrawFilter">
@@ -38,6 +40,15 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <activity
+                android:name="ClipRegionActivity"
+                android:label="_ClipRegion">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
         
         <activity
                 android:name="DisplayListLayersActivity"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
new file mode 100644
index 0000000..b2a508b
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Region;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ClipRegionActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final RegionView view = new RegionView(this);
+        setContentView(view);
+    }
+
+    public static class RegionView extends View {
+        public RegionView(Context c) {
+            super(c);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            canvas.save();
+            canvas.clipRect(100.0f, 100.0f, getWidth() - 100.0f, getHeight() - 100.0f,
+                    Region.Op.DIFFERENCE);
+            canvas.drawARGB(255, 255, 0, 0);
+            canvas.restore();
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
index a7987b3..0ffb0e5 100644
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
@@ -25,13 +25,14 @@
     p.y = -1.f + ((float)y / gDimY) * 2.f;
 
     float2 t = 0;
+    float2 t2 = t * t;
     int iteration = 0;
-    while((t.x*t.x + t.y*t.y < 4.f) && (iteration < gMaxIteration)) {
-        float2 t2 = t * t;
+    while((t2.x + t2.y < 4.f) && (iteration < gMaxIteration)) {
         float xtemp = t2.x - t2.y + p.x;
         t.y = 2 * t.x * t.y + p.y;
         t.x = xtemp;
         iteration++;
+        t2 = t * t;
     }
 
     if(iteration >= gMaxIteration) {
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 3615f60..7368260 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -283,6 +283,9 @@
         mRadius = MAX_RADIUS;
         mScript.set_radius(mRadius);
 
+        mScript.invoke_filter();
+        mRS.finish();
+
         long t = java.lang.System.currentTimeMillis();
 
         mScript.invoke_filter();
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
index f96e68b..912d863 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
@@ -84,7 +84,7 @@
                 Log.v(TAG, "RenderScript framew time core: " + t + " ms");
             }
             long avgValue = sum/ITERATION;
-            rsWriter.write("Averge frame time: " + avgValue + " ms\n");
+            rsWriter.write("Average frame time: " + avgValue + " ms\n");
             Log.v(TAG, "Average frame time: " + avgValue + " ms");
             rsWriter.close();
         } catch (IOException e) {
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
new file mode 100644
index 0000000..656961c
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
@@ -0,0 +1,8 @@
+varying vec2 varTex0;
+
+void main() {
+   lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb;
+   gl_FragColor.xyz = col0 * UNI_modulate.rgb;
+   gl_FragColor.w = UNI_modulate.a;
+}
+
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
index ba70c71..41f664a 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
@@ -35,18 +35,22 @@
     // Custom shaders
     private ProgramFragment mProgFragmentMultitex;
     private ProgramFragment mProgFragmentSingletex;
+    private ProgramFragment mProgFragmentSingletexModulate;
     private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
     int mBenchmarkDimX;
     int mBenchmarkDimY;
 
     private ScriptC_fill_test mFillScript;
     ScriptField_TestScripts_s.Item[] mTests;
+    ScriptField_FillTestFragData_s mFragData;
 
     private final String[] mNames = {
         "Fill screen 10x singletexture",
         "Fill screen 10x 3tex multitexture",
         "Fill screen 10x blended singletexture",
-        "Fill screen 10x blended 3tex multitexture"
+        "Fill screen 10x blended 3tex multitexture",
+        "Fill screen 3x modulate blended singletexture",
+        "Fill screen 1x modulate blended singletexture",
     };
 
     public FillTest() {
@@ -88,6 +92,8 @@
         addTest(index++, 0 /*testId*/, 0 /*blend*/, 10 /*quadCount*/);
         addTest(index++, 1 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
         addTest(index++, 0 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
+        addTest(index++, 2 /*testId*/, 1 /*blend*/, 3 /*quadCount*/);
+        addTest(index++, 2 /*testId*/, 1 /*blend*/, 1 /*quadCount*/);
 
         return true;
     }
@@ -112,6 +118,14 @@
         pfbCustom.setShader(mRes, R.raw.singletexf);
         pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
         mProgFragmentSingletex = pfbCustom.create();
+
+        pfbCustom = new ProgramFragment.Builder(mRS);
+        pfbCustom.setShader(mRes, R.raw.singletexfm);
+        pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+        mFragData = new ScriptField_FillTestFragData_s(mRS, 1);
+        pfbCustom.addConstant(mFragData.getType());
+        mProgFragmentSingletexModulate = pfbCustom.create();
+        mProgFragmentSingletexModulate.bindConstants(mFragData.getAllocation(), 0);
     }
 
     private Allocation loadTextureARGB(int id) {
@@ -140,6 +154,7 @@
         mFillScript.set_gProgVertex(progVertex);
 
         mFillScript.set_gProgFragmentTexture(mProgFragmentSingletex);
+        mFillScript.set_gProgFragmentTextureModulate(mProgFragmentSingletexModulate);
         mFillScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
         mFillScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS));
         mFillScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS));
@@ -150,5 +165,7 @@
         mFillScript.set_gTexOpaque(loadTextureRGB(R.drawable.data));
         mFillScript.set_gTexTransparent(loadTextureARGB(R.drawable.leaf));
         mFillScript.set_gTexChecker(loadTextureRGB(R.drawable.checker));
+
+        mFillScript.bind_gFragData(mFragData);
     }
 }
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
index 23832d3..281f830 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
@@ -21,6 +21,7 @@
 
 rs_program_vertex gProgVertex;
 rs_program_fragment gProgFragmentTexture;
+rs_program_fragment gProgFragmentTextureModulate;
 rs_program_fragment gProgFragmentMultitex;
 
 rs_program_store gProgStoreBlendNone;
@@ -41,6 +42,11 @@
 } FillTestData;
 FillTestData *gData;
 
+typedef struct FillTestFragData_s {
+    float4 modulate;
+} FillTestFragData;
+FillTestFragData *gFragData;
+
 static float gDt = 0.0f;
 
 void init() {
@@ -58,7 +64,7 @@
     rsgProgramVertexLoadProjectionMatrix(&proj);
 }
 
-static void displaySingletexFill(bool blend, int quadCount) {
+static void displaySingletexFill(bool blend, int quadCount, bool modulate) {
     bindProgramVertexOrtho();
     rs_matrix4x4 matrix;
     rsMatrixLoadIdentity(&matrix);
@@ -70,9 +76,21 @@
     } else {
         rsgBindProgramStore(gProgStoreBlendAlpha);
     }
-    rsgBindProgramFragment(gProgFragmentTexture);
-    rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
-    rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+    if (modulate) {
+        rsgBindProgramFragment(gProgFragmentTextureModulate);
+        rsgBindSampler(gProgFragmentTextureModulate, 0, gLinearClamp);
+        rsgBindTexture(gProgFragmentTextureModulate, 0, gTexOpaque);
+
+        gFragData->modulate.r = 0.8f;
+        gFragData->modulate.g = 0.7f;
+        gFragData->modulate.b = 0.8f;
+        gFragData->modulate.a = 0.5f;
+        rsgAllocationSyncAll(rsGetAllocation(gFragData));
+    } else {
+        rsgBindProgramFragment(gProgFragmentTexture);
+        rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+        rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+    }
 
     for (int i = 0; i < quadCount; i ++) {
         float startX = 5 * i, startY = 5 * i;
@@ -128,7 +146,10 @@
             displayMultitextureSample(gData->blend == 1 ? true : false, gData->quadCount);
             break;
         case 1:
-            displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount);
+            displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, false);
+            break;
+        case 2:
+            displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, true);
             break;
         default:
             rsDebug("Wrong test number", 0);
diff --git a/tests/RenderScriptTests/SceneGraph/Android.mk b/tests/RenderScriptTests/SceneGraph/Android.mk
new file mode 100644
index 0000000..ba4b3c5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/Android.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := SceneGraphTest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
new file mode 100644
index 0000000..e8d1e8e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.testapp">
+    <uses-permission
+        android:name="android.permission.INTERNET" />
+    <application android:label="SceneGraphTest">
+        <activity android:name="TestApp"
+                  android:label="SceneGraphTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="FileSelector"
+                  android:label="FileSelector"
+                  android:hardwareAccelerated="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/blue.jpg b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
new file mode 100644
index 0000000..494e77a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
new file mode 100644
index 0000000..2fcecb0
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/green.jpg b/tests/RenderScriptTests/SceneGraph/assets/green.jpg
new file mode 100644
index 0000000..a86a754
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/green.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/grey.jpg b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
new file mode 100644
index 0000000..5870b1a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orange.jpg b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
new file mode 100644
index 0000000..7dbe942
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
new file mode 100644
index 0000000..07318ae
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
new file mode 100644
index 0000000..7eef443f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
@@ -0,0 +1,1102 @@
+<?xml version="1.0" ?>
+<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
+    <asset>
+        <contributor>
+            <author>alexst</author>
+            <authoring_tool>OpenCOLLADA2010</authoring_tool>
+            <comments>ColladaMaya export options: bakeTransforms=0;relativePaths=0;copyTextures=0;exportTriangles=1;exportCgfxFileReferences=0; isSampling=0;curveConstrainSampling=0;removeStaticCurves=1;exportPolygonMeshes=1;exportLights=1; exportCameras=1;exportJointsAndSkin=1;exportAnimations=0;exportInvisibleNodes=0;exportDefaultCameras=0; exportTexCoords=1;exportNormals=1;exportNormalsPerVertex=1;exportVertexColors=0;exportVertexColorsPerVertex=0; exportTexTangents=0;exportTangents=0;exportReferencedMaterials=1;exportMaterialsOnly=0; exportXRefs=1;dereferenceXRefs=1;exportCameraAsLookat=0;cameraXFov=0;cameraYFov=1;doublePrecision=0</comments>
+            <source_data>file:///Volumes/Android/art/orientation_test.mb</source_data>
+        </contributor>
+        <created>2011-09-30T15:31:38</created>
+        <modified>2011-09-30T15:31:38</modified>
+        <unit meter="0.01" name="centimeter" />
+        <up_axis>Y_UP</up_axis>
+    </asset>
+    <library_cameras>
+        <camera id="cameraShape1" name="cameraShape1">
+            <optics>
+                <technique_common>
+                    <perspective>
+                        <yfov>37.8493</yfov>
+                        <aspect_ratio>1.5</aspect_ratio>
+                        <znear>1</znear>
+                        <zfar>400</zfar>
+                    </perspective>
+                </technique_common>
+            </optics>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <film_fit>0</film_fit>
+                    <film_fit_offset>0</film_fit_offset>
+                    <film_offsetX>0</film_offsetX>
+                    <film_offsetY>0</film_offsetY>
+                    <horizontal_aperture>3.599993</horizontal_aperture>
+                    <lens_squeeze>1</lens_squeeze>
+                    <originalMayaNodeId>cameraShape1</originalMayaNodeId>
+                    <vertical_aperture>2.399995</vertical_aperture>
+                </technique>
+            </extra>
+        </camera>
+        <camera id="CameraDistShape" name="CameraDistShape">
+            <optics>
+                <technique_common>
+                    <perspective>
+                        <yfov>37.8493</yfov>
+                        <aspect_ratio>1.5</aspect_ratio>
+                        <znear>1</znear>
+                        <zfar>1000</zfar>
+                    </perspective>
+                </technique_common>
+            </optics>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <film_fit>0</film_fit>
+                    <film_fit_offset>0</film_fit_offset>
+                    <film_offsetX>0</film_offsetX>
+                    <film_offsetY>0</film_offsetY>
+                    <horizontal_aperture>3.599993</horizontal_aperture>
+                    <lens_squeeze>1</lens_squeeze>
+                    <originalMayaNodeId>CameraDistShape</originalMayaNodeId>
+                    <vertical_aperture>2.399995</vertical_aperture>
+                </technique>
+            </extra>
+        </camera>
+    </library_cameras>
+    <library_materials>
+        <material id="Paint1" name="Paint1">
+            <instance_effect url="#Paint1-fx" />
+        </material>
+        <material id="lambert2" name="lambert2">
+            <instance_effect url="#lambert2-fx" />
+        </material>
+        <material id="Plastic" name="Plastic">
+            <instance_effect url="#Plastic-fx" />
+        </material>
+        <material id="Metal" name="Metal">
+            <instance_effect url="#Metal-fx" />
+        </material>
+        <material id="PlasticCenter" name="PlasticCenter">
+            <instance_effect url="#PlasticCenter-fx" />
+        </material>
+        <material id="PlasticRed" name="PlasticRed">
+            <instance_effect url="#PlasticRed-fx" />
+        </material>
+        <material id="lambert10" name="lambert10">
+            <instance_effect url="#lambert10-fx" />
+        </material>
+        <material id="lambert11" name="lambert11">
+            <instance_effect url="#lambert11-fx" />
+        </material>
+    </library_materials>
+    <library_effects>
+        <effect id="Metal-fx">
+            <profile_COMMON>
+                <newparam sid="file23-surface">
+                    <surface type="2D">
+                        <init_from>file23</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file23-sampler">
+                    <sampler2D>
+                        <source>file23-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file23-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="Paint1-fx">
+            <profile_COMMON>
+                <newparam sid="file25-surface">
+                    <surface type="2D">
+                        <init_from>file25</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file25-sampler">
+                    <sampler2D>
+                        <source>file25-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file25-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="Plastic-fx">
+            <profile_COMMON>
+                <newparam sid="file24-surface">
+                    <surface type="2D">
+                        <init_from>file24</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file24-sampler">
+                    <sampler2D>
+                        <source>file24-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file24-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="PlasticCenter-fx">
+            <profile_COMMON>
+                <newparam sid="file24-surface">
+                    <surface type="2D">
+                        <init_from>file24</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file24-sampler">
+                    <sampler2D>
+                        <source>file24-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file24-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="PlasticRed-fx">
+            <profile_COMMON>
+                <newparam sid="file23-surface">
+                    <surface type="2D">
+                        <init_from>file23</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file23-sampler">
+                    <sampler2D>
+                        <source>file23-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file23-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="lambert10-fx">
+            <profile_COMMON>
+                <newparam sid="file28-surface">
+                    <surface type="2D">
+                        <init_from>file28</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file28-sampler">
+                    <sampler2D>
+                        <source>file28-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file28-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="lambert11-fx">
+            <profile_COMMON>
+                <newparam sid="file29-surface">
+                    <surface type="2D">
+                        <init_from>file29</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file29-sampler">
+                    <sampler2D>
+                        <source>file29-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file29-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+        <effect id="lambert2-fx">
+            <profile_COMMON>
+                <newparam sid="file22-surface">
+                    <surface type="2D">
+                        <init_from>file22</init_from>
+                    </surface>
+                </newparam>
+                <newparam sid="file22-sampler">
+                    <sampler2D>
+                        <source>file22-surface</source>
+                    </sampler2D>
+                </newparam>
+                <technique sid="common">
+                    <lambert>
+                        <emission>
+                            <color>0 0 0 1</color>
+                        </emission>
+                        <ambient>
+                            <color>0 0 0 1</color>
+                        </ambient>
+                        <diffuse>
+                            <texture texture="file22-sampler" texcoord="TEX0">
+                                <extra>
+                                    <technique profile="OpenCOLLADAMaya">
+                                        <blend_mode>NONE</blend_mode>
+                                        <coverageU>1</coverageU>
+                                        <coverageV>1</coverageV>
+                                        <fast>0</fast>
+                                        <mirrorU>0</mirrorU>
+                                        <mirrorV>0</mirrorV>
+                                        <noiseU>0</noiseU>
+                                        <noiseV>0</noiseV>
+                                        <offsetU>0</offsetU>
+                                        <offsetV>0</offsetV>
+                                        <repeatU>1</repeatU>
+                                        <repeatV>1</repeatV>
+                                        <rotateFrame>0</rotateFrame>
+                                        <rotateUV>0</rotateUV>
+                                        <stagger>0</stagger>
+                                        <translateFrameU>0</translateFrameU>
+                                        <translateFrameV>0</translateFrameV>
+                                        <wrapU>1</wrapU>
+                                        <wrapV>1</wrapV>
+                                    </technique>
+                                </extra>
+                            </texture>
+                        </diffuse>
+                        <transparent opaque="RGB_ZERO">
+                            <color>0 0 0 1</color>
+                        </transparent>
+                        <transparency>
+                            <float>1</float>
+                        </transparency>
+                    </lambert>
+                </technique>
+            </profile_COMMON>
+        </effect>
+    </library_effects>
+    <library_images>
+        <image id="file29" name="file29" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/blue.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file29</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file25" name="file25" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/carbonfiber.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file25</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file28" name="file28" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/green.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file28</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file22" name="file22" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/grey.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file22</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file24" name="file24" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/orange.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file24</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+        <image id="file23" name="file23" height="0" width="0">
+            <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/red.jpg</init_from>
+            <extra>
+                <technique profile="OpenCOLLADAMaya">
+                    <dgnode_type>kFile</dgnode_type>
+                    <image_sequence>0</image_sequence>
+                    <originalMayaNodeId>file23</originalMayaNodeId>
+                </technique>
+            </extra>
+        </image>
+    </library_images>
+    <library_visual_scenes>
+        <visual_scene id="VisualSceneNode" name="orientation_test">
+            <node id="camera1" name="camera1">
+                <translate sid="translate">24.5791 14.1321 31.4654</translate>
+                <rotate sid="rotateZ">0 0 1 0</rotate>
+                <rotate sid="rotateY">0 1 0 42</rotate>
+                <rotate sid="rotateX">1 0 0 -16.2</rotate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_camera url="#cameraShape1" />
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>camera1</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="CameraAim" name="CameraAim">
+                <translate sid="translate">0.0209301 3.68542 2.06912</translate>
+                <rotate sid="rotateY">0 1 0 43.2561</rotate>
+                <rotate sid="rotateX">1 0 0 -20</rotate>
+                <scale sid="scale">1 1 1</scale>
+                <node id="CameraDist" name="CameraDist">
+                    <translate sid="translate">0 0 45</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_camera url="#CameraDistShape" />
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>CameraDist</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>CameraAim</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere4" name="pSphere4">
+                <translate sid="translate">-9.69237 0 7.70498</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape4">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere4</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere1" name="pSphere1">
+                <translate sid="translate">13.0966 0 5.76254</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape1">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere1</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere2" name="pSphere2">
+                <translate sid="translate">21.7661 0 -13.6375</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape2">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere2</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere3" name="pSphere3">
+                <translate sid="translate">-13.862 0 -13.6154</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape3">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere3</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pSphere5" name="pSphere5">
+                <translate sid="translate">31.0862 0 18.5992</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pSphereShape5">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert7SG" target="#Paint1">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pSphere5</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube1" name="pCube1">
+                <translate sid="translate">0 0 0</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape1">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert4SG" target="#lambert2">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube1</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="group1" name="group1">
+                <translate sid="translate">0 0 0</translate>
+                <rotate sid="rotateZ">0 0 1 -162.693</rotate>
+                <rotate sid="rotateY">0 1 0 21.3345</rotate>
+                <rotate sid="rotateX">1 0 0 -100.567</rotate>
+                <scale sid="scale">1 1 1</scale>
+                <node id="pSphere6" name="pSphere6">
+                    <translate sid="translate">-13.862 0 -13.6154</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape6">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert6SG" target="#Plastic">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere6</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere7" name="pSphere7">
+                    <translate sid="translate">-9.69237 0 7.70498</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape7">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert6SG" target="#Plastic">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere7</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere8" name="pSphere8">
+                    <translate sid="translate">21.7661 0 -13.6375</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape8">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert6SG" target="#Plastic">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere8</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere9" name="pSphere9">
+                    <translate sid="translate">13.0966 0 5.76254</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape9">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert6SG" target="#Plastic">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere9</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>group1</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="group2" name="group2">
+                <translate sid="translate">0 0 0</translate>
+                <rotate sid="rotateZ">0 0 1 45.4017</rotate>
+                <rotate sid="rotateY">0 1 0 79.393</rotate>
+                <rotate sid="rotateX">1 0 0 5.10889</rotate>
+                <scale sid="scale">1 1 1</scale>
+                <node id="pSphere10" name="pSphere10">
+                    <translate sid="translate">31.0862 0 18.5992</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape10">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere10</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere11" name="pSphere11">
+                    <translate sid="translate">13.0966 0 5.76254</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape11">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere11</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere12" name="pSphere12">
+                    <translate sid="translate">7.4784 16.3496 7.36882</translate>
+                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+                    <rotate sid="rotateY">0 1 0 158.666</rotate>
+                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape12">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere12</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere13" name="pSphere13">
+                    <translate sid="translate">-9.69237 0 7.70498</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape13">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere13</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere14" name="pSphere14">
+                    <translate sid="translate">11.3635 -4.3926 2.21012</translate>
+                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+                    <rotate sid="rotateY">0 1 0 158.666</rotate>
+                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape14">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere14</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere15" name="pSphere15">
+                    <translate sid="translate">21.7661 0 -13.6375</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape15">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere15</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere16" name="pSphere16">
+                    <translate sid="translate">-9.5945 -8.92317 -5.74901</translate>
+                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+                    <rotate sid="rotateY">0 1 0 158.666</rotate>
+                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape16">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere16</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere17" name="pSphere17">
+                    <translate sid="translate">-13.862 0 -13.6154</translate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape17">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere17</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <node id="pSphere18" name="pSphere18">
+                    <translate sid="translate">-24.2135 6.497 -5.58935</translate>
+                    <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+                    <rotate sid="rotateY">0 1 0 158.666</rotate>
+                    <rotate sid="rotateX">1 0 0 79.4335</rotate>
+                    <scale sid="scale">1 1 1</scale>
+                    <instance_geometry url="#pSphereShape18">
+                        <bind_material>
+                            <technique_common>
+                                <instance_material symbol="lambert5SG" target="#Metal">
+                                    <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                                </instance_material>
+                            </technique_common>
+                        </bind_material>
+                    </instance_geometry>
+                    <extra>
+                        <technique profile="OpenCOLLADAMaya">
+                            <originalMayaNodeId>pSphere18</originalMayaNodeId>
+                        </technique>
+                    </extra>
+                </node>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>group2</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube2" name="pCube2">
+                <translate sid="translate">0 0 0</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape2">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert8SG" target="#PlasticCenter">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube2</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube3" name="pCube3">
+                <translate sid="translate">15 0 0</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape3">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert9SG" target="#PlasticRed">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube3</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube4" name="pCube4">
+                <translate sid="translate">0 15 0</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape4">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert10SG" target="#lambert10">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube4</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+            <node id="pCube5" name="pCube5">
+                <translate sid="translate">0 0 15</translate>
+                <scale sid="scale">1 1 1</scale>
+                <instance_geometry url="#pCubeShape5">
+                    <bind_material>
+                        <technique_common>
+                            <instance_material symbol="lambert11SG" target="#lambert11">
+                                <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+                            </instance_material>
+                        </technique_common>
+                    </bind_material>
+                </instance_geometry>
+                <extra>
+                    <technique profile="OpenCOLLADAMaya">
+                        <originalMayaNodeId>pCube5</originalMayaNodeId>
+                    </technique>
+                </extra>
+            </node>
+        </visual_scene>
+    </library_visual_scenes>
+    <scene>
+        <instance_visual_scene url="#VisualSceneNode" />
+    </scene>
+</COLLADA>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/paint.jpg b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
new file mode 100644
index 0000000..0791045
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/red.jpg b/tests/RenderScriptTests/SceneGraph/assets/red.jpg
new file mode 100644
index 0000000..320a2a6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/red.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
new file mode 100644
index 0000000..f7353fd
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml
new file mode 100644
index 0000000..9ea30107
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/load_model"
+          android:title="@string/load_model" />
+    <item android:id="@+id/use_blur"
+          android:title="@string/use_blur" />
+</menu>
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
new file mode 100644
index 0000000..fa468cc
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
@@ -0,0 +1,15 @@
+varying vec2 varTex0;
+
+void main() {
+   vec2 blurCoord = varTex0;
+   blurCoord.x = varTex0.x + UNI_blurOffset0;
+   vec3 col = texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.x = varTex0.x + UNI_blurOffset1;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.x = varTex0.x + UNI_blurOffset2;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.x = varTex0.x + UNI_blurOffset3;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+
+   gl_FragColor = vec4(col * 0.25, 0.0); //texture2D(UNI_Tex0, varTex0);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
new file mode 100644
index 0000000..a644a3e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
@@ -0,0 +1,17 @@
+varying vec2 varTex0;
+
+void main() {
+   vec2 blurCoord = varTex0;
+   blurCoord.y = varTex0.y + UNI_blurOffset0;
+   vec3 col = texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.y = varTex0.y + UNI_blurOffset1;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.y = varTex0.y + UNI_blurOffset2;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+   blurCoord.y = varTex0.y + UNI_blurOffset3;
+   col += texture2D(UNI_Tex0, blurCoord).rgb;
+
+   col = col * 0.25;
+
+   gl_FragColor = vec4(col, 0.0); //texture2D(UNI_Tex0, varTex0);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
new file mode 100644
index 0000000..bc824b6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
@@ -0,0 +1,7 @@
+varying vec2 varTex0;
+
+void main() {
+   gl_Position = ATTRIB_position;
+   varTex0 = ATTRIB_texture0;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
new file mode 100644
index 0000000..5d8938b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
@@ -0,0 +1,19 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = (varWorldNormal);
+
+   vec3 light0Vec = V;
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = dot(worldNorm, light0Vec);
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * light0_Diffuse * 1.2;
+   gl_FragColor = col; //vec4(0.0, 1.0, 0.0, 0.0);
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
new file mode 100644
index 0000000..51f0612
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
@@ -0,0 +1,23 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = V;
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, 15.0) * 0.5;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * (textureCube(UNI_Tex1, worldNorm).rgb * 0.5 + vec3(light0_Diffuse));
+   col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
new file mode 100644
index 0000000..893d553
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
@@ -0,0 +1,26 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = V;
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.01, 0.99);
+   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, 150.0) * 0.5;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * light0_Diffuse * 1.1;
+   col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+
+   float fresnel = mix(pow(1.0 - light0_Diffuse, 15.0), 1.0, 0.1);
+   col.xyz = mix(col.xyz, textureCube(UNI_Tex1, -light0R).rgb * 2.4, fresnel);
+   col.w = 0.8;
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
new file mode 100644
index 0000000..ceb53bd
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
@@ -0,0 +1,22 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = V;
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, 10.0) * 0.5;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+   col.xyz = col.xyz * light0_Diffuse * 1.2;
+   col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
new file mode 100644
index 0000000..b253622
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
@@ -0,0 +1,29 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+   vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+   vec3 worldNorm = normalize(varWorldNormal);
+
+   vec3 light0Vec = normalize(UNI_lightPos_0.xyz - varWorldPos.xyz);
+   vec3 light0R = reflect(light0Vec, worldNorm);
+   float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+   float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+   float light0_Specular = pow(light0Spec, 10.0) * 0.7;
+
+   vec3 light1Vec = normalize(UNI_lightPos_1.xyz - varWorldPos.xyz);
+   vec3 light1R = reflect(light1Vec, worldNorm);
+   float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0);
+   float light1Spec = clamp(dot(-light1R, V), 0.001, 1.0);
+   float light1_Specular = pow(light1Spec, 10.0) * 0.7;
+
+   vec2 t0 = varTex0.xy;
+   lowp vec4 col = UNI_diffuse;
+   col.xyz = col.xyz * (light0_Diffuse * UNI_lightColor_0.xyz +
+                        light1_Diffuse * UNI_lightColor_1.xyz);
+   col.xyz += (light0_Specular + light1_Specular);
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
new file mode 100644
index 0000000..f48895c
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
new file mode 100644
index 0000000..42b231a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
@@ -0,0 +1,13 @@
+varying vec2 varTex0;
+
+void main() {
+   vec3 col = texture2D(UNI_Tex0, varTex0).rgb;
+
+   vec3 desat = vec3(0.299, 0.587, 0.114);
+   float lum = dot(desat, col);
+   float stepVal = step(lum, 0.8);
+   col = mix(col, vec3(0.0), stepVal)*0.5;
+
+   gl_FragColor = vec4(col, 0.0);
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
new file mode 100644
index 0000000..1ea234f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
@@ -0,0 +1,17 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+   vec4 objPos = ATTRIB_position;
+   vec4 worldPos = UNI_model * objPos;
+   gl_Position = UNI_viewProj * worldPos;
+
+   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+   vec3 worldNorm = model3 * ATTRIB_normal;
+
+   varWorldPos = worldPos.xyz;
+   varWorldNormal = worldNorm;
+   varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
new file mode 100644
index 0000000..dd709cf
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
@@ -0,0 +1,7 @@
+varying vec2 varTex0;
+
+void main() {
+   lowp vec4 col = texture2D(UNI_Tex0, varTex0).rgba;
+   gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/values/strings.xml b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml
new file mode 100644
index 0000000..c916d79
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <skip />
+    <string name="load_model">Load Model</string>
+    <string name="use_blur">Use Blur</string>
+</resources>
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
new file mode 100644
index 0000000..42f2be5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.*;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Camera extends SceneGraphBase {
+
+    Transform mTransform;
+
+    ScriptField_Camera_s.Item mData;
+    ScriptField_Camera_s mField;
+
+    public Camera() {
+        mData = new ScriptField_Camera_s.Item();
+        mData.near = 0.1f;
+        mData.far = 1000.0f;
+        mData.horizontalFOV = 60.0f;
+        mData.aspect = 0;
+    }
+
+    public void setTransform(Transform t) {
+        mTransform = t;
+        if (mField != null) {
+            mField.set_transformMatrix(0, mTransform.getRSData().getAllocation(), true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+    public void setFOV(float fov) {
+        mData.horizontalFOV = fov;
+        if (mField != null) {
+            mField.set_horizontalFOV(0, fov, true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+
+    public void setNear(float n) {
+        mData.near = n;
+        if (mField != null) {
+            mField.set_near(0, n, true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+
+    public void setFar(float f) {
+        mData.far = f;
+        if (mField != null) {
+            mField.set_far(0, f, true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+
+    public void setName(String n) {
+        super.setName(n);
+        if (mField != null) {
+            RenderScriptGL rs = SceneManager.getRS();
+            mData.name = getNameAlloc(rs);
+            mField.set_name(0, mData.name, true);
+            mField.set_isDirty(0, 1, true);
+        }
+    }
+
+    ScriptField_Camera_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+
+        if (mTransform == null) {
+            throw new RuntimeException("Cameras without transforms are invalid");
+        }
+
+        mField = new ScriptField_Camera_s(rs, 1);
+
+        mData.transformMatrix = mTransform.getRSData().getAllocation();
+        mData.transformTimestamp = 1;
+        mData.timestamp = 1;
+        mData.isDirty = 1;
+        mData.name = getNameAlloc(rs);
+        mField.set(mData, 0, true);
+
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
new file mode 100644
index 0000000..d954313
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
@@ -0,0 +1,563 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+package com.android.scenegraph;

+import com.android.scenegraph.CompoundTransform.TranslateComponent;

+import com.android.scenegraph.CompoundTransform.RotateComponent;

+import com.android.scenegraph.CompoundTransform.ScaleComponent;

+import java.io.IOException;

+import java.io.InputStream;

+import java.util.ArrayList;

+import java.util.Iterator;

+import java.util.List;

+import java.util.StringTokenizer;

+import java.util.HashMap;

+

+import javax.xml.parsers.DocumentBuilder;

+import javax.xml.parsers.DocumentBuilderFactory;

+import javax.xml.parsers.ParserConfigurationException;

+

+import org.w3c.dom.Document;

+import org.w3c.dom.Element;

+import org.w3c.dom.Node;

+import org.w3c.dom.NodeList;

+import org.xml.sax.SAXException;

+

+import android.renderscript.*;

+import android.util.Log;

+

+public class ColladaParser {

+    static final String TAG = "ColladaParser";

+    Document mDom;

+

+    HashMap<String, LightBase> mLights;

+    HashMap<String, Camera> mCameras;

+    HashMap<String, ArrayList<ShaderParam> > mEffectsParams;

+    HashMap<String, Texture2D> mImages;

+    HashMap<String, Texture2D> mSamplerImageMap;

+    HashMap<String, String> mMeshIdNameMap;

+    Scene mScene;

+

+    String mRootDir;

+

+    String toString(Float3 v) {

+        String valueStr = v.x + " " + v.y + " " + v.z;

+        return valueStr;

+    }

+

+    String toString(Float4 v) {

+        String valueStr = v.x + " " + v.y + " " + v.z + " " + v.w;

+        return valueStr;

+    }

+

+    public ColladaParser(){

+        mLights = new HashMap<String, LightBase>();

+        mCameras = new HashMap<String, Camera>();

+        mEffectsParams = new HashMap<String, ArrayList<ShaderParam> >();

+        mImages = new HashMap<String, Texture2D>();

+        mMeshIdNameMap = new HashMap<String, String>();

+    }

+

+    public void init(InputStream is, String rootDir) {

+        mLights.clear();

+        mCameras.clear();

+        mEffectsParams.clear();

+

+        mRootDir = rootDir;

+

+        long start = System.currentTimeMillis();

+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

+        try {

+            DocumentBuilder db = dbf.newDocumentBuilder();

+            mDom = db.parse(is);

+        } catch(ParserConfigurationException e) {

+            e.printStackTrace();

+        } catch(SAXException e) {

+            e.printStackTrace();

+        } catch(IOException e) {

+            e.printStackTrace();

+        }

+        long end = System.currentTimeMillis();

+        Log.v("TIMER", "    Parse time: " + (end - start));

+        exportSceneData();

+    }

+

+    Scene getScene() {

+        return mScene;

+    }

+

+    private void exportSceneData(){

+        mScene = new Scene();

+

+        Element docEle = mDom.getDocumentElement();

+        NodeList nl = docEle.getElementsByTagName("light");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element l = (Element)nl.item(i);

+                convertLight(l);

+            }

+        }

+

+        nl = docEle.getElementsByTagName("camera");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element c = (Element)nl.item(i);

+                convertCamera(c);

+            }

+        }

+

+        nl = docEle.getElementsByTagName("image");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element img = (Element)nl.item(i);

+                convertImage(img);

+            }

+        }

+

+        nl = docEle.getElementsByTagName("effect");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element e = (Element)nl.item(i);

+                convertEffects(e);

+            }

+        }

+

+        // Material is just a link to the effect

+        nl = docEle.getElementsByTagName("material");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element m = (Element)nl.item(i);

+                convertMaterials(m);

+            }

+        }

+

+        // Look through the geometry list and build up a correlation between id's and names

+        nl = docEle.getElementsByTagName("geometry");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element m = (Element)nl.item(i);

+                convertGeometries(m);

+            }

+        }

+

+

+        nl = docEle.getElementsByTagName("visual_scene");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element s = (Element)nl.item(i);

+                getScene(s);

+            }

+        }

+    }

+

+    private void getRenderable(Element shape, Transform t) {

+        String geoURL = shape.getAttribute("url").substring(1);

+        String geoName = mMeshIdNameMap.get(geoURL);

+        if (geoName != null) {

+            geoURL = geoName;

+        }

+        //RenderableGroup group = new RenderableGroup();

+        //group.setName(geoURL.substring(1));

+        //mScene.appendRenderable(group);

+        NodeList nl = shape.getElementsByTagName("instance_material");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element materialRef = (Element)nl.item(i);

+                String meshIndexName = materialRef.getAttribute("symbol");

+                String materialName = materialRef.getAttribute("target");

+

+                Renderable d = new Renderable();

+                d.setMesh(geoURL, meshIndexName);

+                d.setMaterialName(materialName.substring(1));

+                d.setName(geoURL);

+

+                //Log.v(TAG, "Created drawable geo " + geoURL + " index " + meshIndexName + " material " + materialName);

+

+                d.setTransform(t);

+                //Log.v(TAG, "Set source param " + t.getName());

+

+                // Now find all the parameters that exist on the material

+                ArrayList<ShaderParam> materialParams;

+                materialParams = mEffectsParams.get(materialName.substring(1));

+                for (int pI = 0; pI < materialParams.size(); pI ++) {

+                    d.appendSourceParams(materialParams.get(pI));

+                    //Log.v(TAG, "Set source param i: " + pI + " name " + materialParams.get(pI).getParamName());

+                }

+                mScene.appendRenderable(d);

+                //group.appendChildren(d);

+            }

+        }

+    }

+

+    private void updateLight(Element shape, Transform t) {

+        String lightURL = shape.getAttribute("url");

+        // collada uses a uri structure to link things,

+        // but we ignore it for now and do a simple search

+        LightBase light = mLights.get(lightURL.substring(1));

+        if (light != null) {

+            light.setTransform(t);

+            //Log.v(TAG, "Set Light " + light.getName() + " " + t.getName());

+        }

+    }

+

+    private void updateCamera(Element shape, Transform t) {

+        String camURL = shape.getAttribute("url");

+        // collada uses a uri structure to link things,

+        // but we ignore it for now and do a simple search

+        Camera cam = mCameras.get(camURL.substring(1));

+        if (cam != null) {

+            cam.setTransform(t);

+            //Log.v(TAG, "Set Camera " + cam.getName() + " " + t.getName());

+        }

+    }

+

+    private void getNode(Element node, Transform parent, String indent) {

+        String name = node.getAttribute("name");

+        String id = node.getAttribute("id");

+        CompoundTransform current = new CompoundTransform();

+        current.setName(name);

+        if (parent != null) {

+            parent.appendChild(current);

+        } else {

+            mScene.appendTransform(current);

+        }

+

+        mScene.addToTransformMap(current);

+

+        //Log.v(TAG, indent + "|");

+        //Log.v(TAG, indent + "[" + name + "]");

+

+        Node childNode = node.getFirstChild();

+        while (childNode != null) {

+            if (childNode.getNodeType() == Node.ELEMENT_NODE) {

+                Element field = (Element)childNode;

+                String fieldName = field.getTagName();

+                String description = field.getAttribute("sid");

+                if (fieldName.equals("translate")) {

+                    Float3 value = getFloat3(field);

+                    current.addComponent(new TranslateComponent(description, value));

+                    //Log.v(TAG, indent + " translate " + description + toString(value));

+                } else if (fieldName.equals("rotate")) {

+                    Float4 value = getFloat4(field);

+                    //Log.v(TAG, indent + " rotate " + description + toString(value));

+                    Float3 axis = new Float3(value.x, value.y, value.z);

+                    current.addComponent(new RotateComponent(description, axis, value.w));

+                } else if (fieldName.equals("scale")) {

+                    Float3 value = getFloat3(field);

+                    //Log.v(TAG, indent + " scale " + description + toString(value));

+                    current.addComponent(new ScaleComponent(description, value));

+                } else if (fieldName.equals("instance_geometry")) {

+                    getRenderable(field, current);

+                } else if (fieldName.equals("instance_light")) {

+                    updateLight(field, current);

+                } else if (fieldName.equals("instance_camera")) {

+                    updateCamera(field, current);

+                } else if (fieldName.equals("node")) {

+                    getNode(field, current, indent + "   ");

+                }

+            }

+            childNode = childNode.getNextSibling();

+        }

+    }

+

+    // This will find the actual texture node, which is sometimes hidden behind a sampler

+    // and sometimes referenced directly

+    Texture2D getTexture(String samplerName) {

+        String texName = samplerName;

+

+        // Check to see if the image file is hidden by a sampler surface link combo

+        Element sampler = mDom.getElementById(samplerName);

+        if (sampler != null) {

+            NodeList nl = sampler.getElementsByTagName("source");

+            if (nl != null && nl.getLength() == 1) {

+                Element ref = (Element)nl.item(0);

+                String surfaceName = getString(ref);

+                if (surfaceName == null) {

+                    return null;

+                }

+

+                Element surface = mDom.getElementById(surfaceName);

+                if (surface == null) {

+                    return null;

+                }

+                nl = surface.getElementsByTagName("init_from");

+                if (nl != null && nl.getLength() == 1) {

+                    ref = (Element)nl.item(0);

+                    texName = getString(ref);

+                }

+            }

+        }

+

+        //Log.v(TAG, "Extracted texture name " + texName);

+        return mImages.get(texName);

+    }

+

+    void extractParams(Element fx, ArrayList<ShaderParam> params) {

+        Node paramNode = fx.getFirstChild();

+        while (paramNode != null) {

+            if (paramNode.getNodeType() == Node.ELEMENT_NODE) {

+                String name = paramNode.getNodeName();

+                // Now find what type it is

+                Node typeNode = paramNode.getFirstChild();

+                while (typeNode != null && typeNode.getNodeType() != Node.ELEMENT_NODE) {

+                    typeNode = typeNode.getNextSibling();

+                }

+                String paramType = typeNode.getNodeName();

+                Element typeElem = (Element)typeNode;

+                ShaderParam sceneParam = null;

+                if (paramType.equals("color")) {

+                    Float4Param f4p = new Float4Param(name);

+                    Float4 value = getFloat4(typeElem);

+                    f4p.setValue(value);

+                    sceneParam = f4p;

+                    //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + toString(value));

+                } else if (paramType.equals("float")) {

+                    Float4Param f4p = new Float4Param(name);

+                    float value = getFloat(typeElem);

+                    f4p.setValue(new Float4(value, value, value, value));

+                    sceneParam = f4p;

+                    //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + value);

+                }  else if (paramType.equals("texture")) {

+                    String samplerName = typeElem.getAttribute("texture");

+                    Texture2D tex = getTexture(samplerName);

+                    TextureParam texP = new TextureParam(name);

+                    texP.setTexture(tex);

+                    sceneParam = texP;

+                    //Log.v(TAG, "Extracted texture " + tex);

+                }

+                if (sceneParam != null) {

+                    params.add(sceneParam);

+                }

+            }

+            paramNode = paramNode.getNextSibling();

+        }

+    }

+

+    private void convertMaterials(Element mat) {

+        String id = mat.getAttribute("id");

+        NodeList nl = mat.getElementsByTagName("instance_effect");

+        if (nl != null && nl.getLength() == 1) {

+            Element ref = (Element)nl.item(0);

+            String url = ref.getAttribute("url");

+            ArrayList<ShaderParam> params = mEffectsParams.get(url.substring(1));

+            mEffectsParams.put(id, params);

+        }

+    }

+

+    private void convertGeometries(Element geo) {

+        String id = geo.getAttribute("id");

+        String name = geo.getAttribute("name");

+        if (!id.equals(name)) {

+            mMeshIdNameMap.put(id, name);

+        }

+    }

+

+    private void convertEffects(Element fx) {

+        String id = fx.getAttribute("id");

+        ArrayList<ShaderParam> params = new ArrayList<ShaderParam>();

+

+        NodeList nl = fx.getElementsByTagName("newparam");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element field = (Element)nl.item(i);

+                field.setIdAttribute("sid", true);

+            }

+        }

+

+        nl = fx.getElementsByTagName("blinn");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element field = (Element)nl.item(i);

+                //Log.v(TAG, "blinn");

+                extractParams(field, params);

+            }

+        }

+        nl = fx.getElementsByTagName("lambert");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element field = (Element)nl.item(i);

+                //Log.v(TAG, "lambert");

+                extractParams(field, params);

+            }

+        }

+        nl = fx.getElementsByTagName("phong");

+        if (nl != null) {

+            for(int i = 0; i < nl.getLength(); i++) {

+                Element field = (Element)nl.item(i);

+                //Log.v(TAG, "phong");

+                extractParams(field, params);

+            }

+        }

+        mEffectsParams.put(id, params);

+    }

+

+    private void convertLight(Element light) {

+        String name = light.getAttribute("name");

+        String id = light.getAttribute("id");

+

+        // Determine type

+        String[] knownTypes = { "point", "spot", "directional" };

+        final int POINT_LIGHT = 0;

+        final int SPOT_LIGHT = 1;

+        final int DIR_LIGHT = 2;

+        int type = -1;

+        for (int i = 0; i < knownTypes.length; i ++) {

+            NodeList nl = light.getElementsByTagName(knownTypes[i]);

+            if (nl != null && nl.getLength() != 0) {

+                type = i;

+                break;

+            }

+        }

+

+        //Log.v(TAG, "Found Light Type " + type);

+

+        LightBase sceneLight = null;

+        switch (type) {

+        case POINT_LIGHT:

+            sceneLight = new PointLight();

+            break;

+        case SPOT_LIGHT: // TODO: finish light types

+            break;

+        case DIR_LIGHT: // TODO: finish light types

+            break;

+        }

+

+        if (sceneLight == null) {

+            return;

+        }

+

+        Float3 color = getFloat3(light, "color");

+        sceneLight.setColor(color.x, color.y, color.z);

+        sceneLight.setName(name);

+        mScene.appendLight(sceneLight);

+        mLights.put(id, sceneLight);

+

+        //Log.v(TAG, "Light " + name + " color " + toString(color));

+    }

+

+    private void convertCamera(Element camera) {

+        String name = camera.getAttribute("name");

+        String id = camera.getAttribute("id");

+        float fov = 30.0f;

+        if (getString(camera, "yfov") != null) {

+            fov = getFloat(camera, "yfov");

+        } else if(getString(camera, "xfov") != null) {

+            float aspect = getFloat(camera, "aspect_ratio");

+            fov = getFloat(camera, "xfov") / aspect;

+        }

+

+        float near = getFloat(camera, "znear");

+        float far = getFloat(camera, "zfar");

+

+        Camera sceneCamera = new Camera();

+        sceneCamera.setFOV(fov);

+        sceneCamera.setNear(near);

+        sceneCamera.setFar(far);

+        sceneCamera.setName(name);

+        mScene.appendCamera(sceneCamera);

+        mCameras.put(id, sceneCamera);

+    }

+

+    private void convertImage(Element img) {

+        String name = img.getAttribute("name");

+        String id = img.getAttribute("id");

+        String file = getString(img, "init_from");

+

+        Texture2D tex = new Texture2D();

+        tex.setFileName(file);

+        tex.setFileDir(mRootDir);

+        mScene.appendTextures(tex);

+        mImages.put(id, tex);

+    }

+

+    private void getScene(Element scene) {

+        String name = scene.getAttribute("name");

+        String id = scene.getAttribute("id");

+

+        Node childNode = scene.getFirstChild();

+        while (childNode != null) {

+            if (childNode.getNodeType() == Node.ELEMENT_NODE) {

+                String indent = "";

+                getNode((Element)childNode, null, indent);

+            }

+            childNode = childNode.getNextSibling();

+        }

+    }

+

+    private String getString(Element elem, String name) {

+        String text = null;

+        NodeList nl = elem.getElementsByTagName(name);

+        if (nl != null && nl.getLength() != 0) {

+            text = ((Element)nl.item(0)).getFirstChild().getNodeValue();

+        }

+        return text;

+    }

+

+    private String getString(Element elem) {

+        String text = null;

+        text = elem.getFirstChild().getNodeValue();

+        return text;

+    }

+

+    private int getInt(Element elem, String name) {

+        return Integer.parseInt(getString(elem, name));

+    }

+

+    private float getFloat(Element elem, String name) {

+        return Float.parseFloat(getString(elem, name));

+    }

+

+    private float getFloat(Element elem) {

+        return Float.parseFloat(getString(elem));

+    }

+

+    private Float3 parseFloat3(String valueString) {

+        StringTokenizer st = new StringTokenizer(valueString);

+        float x = Float.parseFloat(st.nextToken());

+        float y = Float.parseFloat(st.nextToken());

+        float z = Float.parseFloat(st.nextToken());

+        return new Float3(x, y, z);

+    }

+

+    private Float4 parseFloat4(String valueString) {

+        StringTokenizer st = new StringTokenizer(valueString);

+        float x = Float.parseFloat(st.nextToken());

+        float y = Float.parseFloat(st.nextToken());

+        float z = Float.parseFloat(st.nextToken());

+        float w = Float.parseFloat(st.nextToken());

+        return new Float4(x, y, z, w);

+    }

+

+    private Float3 getFloat3(Element elem, String name) {

+        String valueString = getString(elem, name);

+        return parseFloat3(valueString);

+    }

+

+    private Float4 getFloat4(Element elem, String name) {

+        String valueString = getString(elem, name);

+        return parseFloat4(valueString);

+    }

+

+    private Float3 getFloat3(Element elem) {

+        String valueString = getString(elem);

+        return parseFloat3(valueString);

+    }

+

+    private Float4 getFloat4(Element elem) {

+        String valueString = getString(elem);

+        return parseFloat4(valueString);

+    }

+}

diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
new file mode 100644
index 0000000..301075e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+import com.android.scenegraph.SceneManager.SceneLoadedCallback;
+
+
+public class ColladaScene {
+
+    private String modelName;
+    private static String TAG = "ColladaScene";
+    private final int STATE_LAST_FOCUS = 1;
+    boolean mLoadFromSD = false;
+
+    SceneLoadedCallback mCallback;
+
+    public ColladaScene(String name, SceneLoadedCallback cb) {
+        modelName = name;
+        mCallback = cb;
+    }
+
+    public void init(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mRes = res;
+
+        mLoadFromSD = SceneManager.isSDCardPath(modelName);
+
+        new ColladaLoaderTask().execute(modelName);
+    }
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    Scene mActiveScene;
+
+    private class ColladaLoaderTask extends AsyncTask<String, Void, Boolean> {
+        ColladaParser sceneSource;
+        protected Boolean doInBackground(String... names) {
+            String rootDir = names[0].substring(0, names[0].lastIndexOf('/') + 1);
+            long start = System.currentTimeMillis();
+            sceneSource = new ColladaParser();
+            InputStream is = null;
+            try {
+                if (!mLoadFromSD) {
+                    is = mRes.getAssets().open(names[0]);
+                } else {
+                    File f = new File(names[0]);
+                    is = new BufferedInputStream(new FileInputStream(f));
+                }
+            } catch (IOException e) {
+                Log.e(TAG, "Could not open collada file");
+                return new Boolean(false);
+            }
+            long end = System.currentTimeMillis();
+            Log.v("TIMER", "Stream load time: " + (end - start));
+
+            start = System.currentTimeMillis();
+            sceneSource.init(is, rootDir);
+            end = System.currentTimeMillis();
+            Log.v("TIMER", "Collada parse time: " + (end - start));
+            return new Boolean(true);
+        }
+
+        protected void onPostExecute(Boolean result) {
+            mActiveScene = sceneSource.getScene();
+            if (mCallback != null) {
+                mCallback.mLoadedScene = mActiveScene;
+                mCallback.run();
+            }
+
+            String shortName = modelName.substring(0, modelName.lastIndexOf('.'));
+            new A3DLoaderTask().execute(shortName + ".a3d");
+        }
+    }
+
+    private class A3DLoaderTask extends AsyncTask<String, Void, Boolean> {
+        protected Boolean doInBackground(String... names) {
+            long start = System.currentTimeMillis();
+            FileA3D model;
+            if (!mLoadFromSD) {
+                model = FileA3D.createFromAsset(mRS, mRes.getAssets(), names[0]);
+            } else {
+                model = FileA3D.createFromFile(mRS, names[0]);
+            }
+            int numModels = model.getIndexEntryCount();
+            for (int i = 0; i < numModels; i ++) {
+                FileA3D.IndexEntry entry = model.getIndexEntry(i);
+                if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+                    mActiveScene.meshLoaded(entry.getMesh());
+                }
+            }
+            long end = System.currentTimeMillis();
+            Log.v("TIMER", "A3D load time: " + (end - start));
+            return new Boolean(true);
+        }
+
+        protected void onPostExecute(Boolean result) {
+        }
+    }
+
+}
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
new file mode 100644
index 0000000..d995dd0
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.*;
+import android.renderscript.Float3;
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class CompoundTransform extends Transform {
+
+    public static abstract class Component {
+        String mName;
+        CompoundTransform mParent;
+        int mParentIndex;
+        protected ScriptField_TransformComponent_s.Item mData;
+
+        Component(int type, String name) {
+            mData = new ScriptField_TransformComponent_s.Item();
+            mData.type = type;
+            mName = name;
+        }
+
+        void setNameAlloc() {
+            RenderScriptGL rs = SceneManager.getRS();
+            if (mData.name != null)  {
+                return;
+            }
+            mData.name = SceneManager.getCachedAlloc(getName());
+            if (mData.name == null) {
+                mData.name = SceneManager.getStringAsAllocation(rs, getName());
+                SceneManager.cacheAlloc(getName(), mData.name);
+            }
+        }
+
+        ScriptField_TransformComponent_s.Item getRSData() {
+            setNameAlloc();
+            return mData;
+        }
+
+        protected void update() {
+            if (mParent != null) {
+                mParent.updateRSComponent(this);
+            }
+        }
+
+        public String getName() {
+            return mName;
+        }
+    }
+
+    public static class TranslateComponent extends Component {
+        public TranslateComponent(String name, Float3 translate) {
+            super(ScriptC_export.const_Transform_TRANSLATE, name);
+            setValue(translate);
+        }
+        public Float3 getValue() {
+            return new Float3(mData.value.x, mData.value.y, mData.value.z);
+        }
+        public void setValue(Float3 val) {
+            mData.value.x = val.x;
+            mData.value.y = val.y;
+            mData.value.z = val.z;
+            update();
+        }
+    }
+
+    public static class RotateComponent extends Component {
+        public RotateComponent(String name, Float3 axis, float angle) {
+            super(ScriptC_export.const_Transform_ROTATE, name);
+            setAxis(axis);
+            setAngle(angle);
+        }
+        public Float3 getAxis() {
+            return new Float3(mData.value.x, mData.value.y, mData.value.z);
+        }
+        public float getAngle() {
+            return mData.value.w;
+        }
+        public void setAxis(Float3 val) {
+            mData.value.x = val.x;
+            mData.value.y = val.y;
+            mData.value.z = val.z;
+            update();
+        }
+        public void setAngle(float val) {
+            mData.value.w = val;
+            update();
+        }
+    }
+
+    public static class ScaleComponent extends Component {
+        public ScaleComponent(String name, Float3 scale) {
+            super(ScriptC_export.const_Transform_SCALE, name);
+            setValue(scale);
+        }
+        public Float3 getValue() {
+            return new Float3(mData.value.x, mData.value.y, mData.value.z);
+        }
+        public void setValue(Float3 val) {
+            mData.value.x = val.x;
+            mData.value.y = val.y;
+            mData.value.z = val.z;
+            update();
+        }
+    }
+
+    ScriptField_TransformComponent_s mComponentField;
+    public ArrayList<Component> mTransformComponents;
+
+    public CompoundTransform() {
+        mTransformComponents = new ArrayList<Component>();
+    }
+
+    public void addComponent(Component c) {
+        if (c.mParent != null) {
+            throw new IllegalArgumentException("Transform components may not be shared");
+        }
+        c.mParent = this;
+        c.mParentIndex = mTransformComponents.size();
+        mTransformComponents.add(c);
+        updateRSComponentAllocation();
+    }
+
+    public void setComponent(int index, Component c) {
+        if (c.mParent != null) {
+            throw new IllegalArgumentException("Transform components may not be shared");
+        }
+        if (index >= mTransformComponents.size()) {
+            throw new IllegalArgumentException("Invalid component index");
+        }
+        c.mParent = this;
+        c.mParentIndex = index;
+        mTransformComponents.set(index, c);
+        updateRSComponent(c);
+    }
+
+    void updateRSComponent(Component c) {
+        if (mField == null || mComponentField == null) {
+            return;
+        }
+        mComponentField.set(c.getRSData(), c.mParentIndex, true);
+        mField.set_isDirty(0, 1, true);
+    }
+
+    void updateRSComponentAllocation() {
+        if (mField == null) {
+            return;
+        }
+        initLocalData();
+
+        mField.set_components(0, mTransformData.components, false);
+        mField.set_isDirty(0, 1, true);
+    }
+
+    void initLocalData() {
+        RenderScriptGL rs = SceneManager.getRS();
+        int numComponenets = mTransformComponents.size();
+        if (numComponenets > 0) {
+            mComponentField = new ScriptField_TransformComponent_s(rs, numComponenets);
+            for (int i = 0; i < numComponenets; i ++) {
+                Component ith = mTransformComponents.get(i);
+                mComponentField.set(ith.getRSData(), i, false);
+            }
+            mComponentField.copyAll();
+
+            mTransformData.components = mComponentField.getAllocation();
+        }
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
new file mode 100644
index 0000000..1502458
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.Scene;
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.Element;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Float4Param extends ShaderParam {
+    private static String TAG = "Float4Param";
+
+    LightBase mLight;
+
+    public Float4Param(String name) {
+        super(name);
+    }
+
+    public Float4Param(String name, float x) {
+        super(name);
+        set(x, 0, 0, 0);
+    }
+
+    public Float4Param(String name, float x, float y) {
+        super(name);
+        set(x, y, 0, 0);
+    }
+
+    public Float4Param(String name, float x, float y, float z) {
+        super(name);
+        set(x, y, z, 0);
+    }
+
+    public Float4Param(String name, float x, float y, float z, float w) {
+        super(name);
+        set(x, y, z, w);
+    }
+
+    void set(float x, float y, float z, float w) {
+        mData.float_value.x = x;
+        mData.float_value.y = y;
+        mData.float_value.z = z;
+        mData.float_value.w = w;
+        if (mField != null) {
+            mField.set_float_value(0, mData.float_value, true);
+        }
+        incTimestamp();
+    }
+
+    public void setValue(Float4 v) {
+        set(v.x, v.y, v.z, v.w);
+    }
+
+    public Float4 getValue() {
+        return mData.float_value;
+    }
+
+    public void setLight(LightBase l) {
+        mLight = l;
+        if (mField != null) {
+            mData.light = mLight.getRSData().getAllocation();
+            mField.set_light(0, mData.light, true);
+        }
+        incTimestamp();
+    }
+
+    boolean findLight(String property) {
+        String indexStr = mParamName.substring(property.length() + 1);
+        if (indexStr == null) {
+            Log.e(TAG, "Invalid light index.");
+            return false;
+        }
+        int index = Integer.parseInt(indexStr);
+        if (index == -1) {
+            return false;
+        }
+        Scene parentScene = SceneManager.getInstance().getActiveScene();
+        ArrayList<LightBase> allLights = parentScene.getLights();
+        if (index >= allLights.size()) {
+            return false;
+        }
+        mLight = allLights.get(index);
+        if (mLight == null) {
+            return false;
+        }
+        return true;
+    }
+
+    int getTypeFromName() {
+        int paramType = ScriptC_export.const_ShaderParam_FLOAT4_DATA;
+        if (mParamName.equalsIgnoreCase(cameraPos)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_POS;
+        } else if(mParamName.equalsIgnoreCase(cameraDir)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_DIR;
+        } else if(mParamName.startsWith(lightColor) && findLight(lightColor)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_COLOR;
+        } else if(mParamName.startsWith(lightPos) && findLight(lightPos)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_POS;
+        } else if(mParamName.startsWith(lightDir) && findLight(lightDir)) {
+            paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_DIR;
+        }
+        return paramType;
+    }
+
+    void initLocalData() {
+        mData.type = getTypeFromName();
+        if (mCamera != null) {
+            mData.camera = mCamera.getRSData().getAllocation();
+        }
+        if (mLight != null) {
+            mData.light = mLight.getRSData().getAllocation();
+        }
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
new file mode 100644
index 0000000..c8cc3ac
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramFragment.Builder;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class FragmentShader extends Shader {
+    ProgramFragment mProgram;
+    ScriptField_FragmentShader_s mField;
+
+    public static class Builder {
+
+        FragmentShader mShader;
+        ProgramFragment.Builder mBuilder;
+
+        public Builder(RenderScriptGL rs) {
+            mShader = new FragmentShader();
+            mBuilder = new ProgramFragment.Builder(rs);
+        }
+
+        public Builder setShader(Resources resources, int resourceID) {
+            mBuilder.setShader(resources, resourceID);
+            return this;
+        }
+
+        public Builder setObjectConst(Type type) {
+            mShader.mPerObjConstants = type;
+            return this;
+        }
+
+        public Builder setShaderConst(Type type) {
+            mShader.mPerShaderConstants = type;
+            return this;
+        }
+
+        public Builder addShaderTexture(Program.TextureType texType, String name) {
+            mShader.mShaderTextureNames.add(name);
+            mShader.mShaderTextureTypes.add(texType);
+            return this;
+        }
+
+        public Builder addTexture(Program.TextureType texType, String name) {
+            mShader.mTextureNames.add(name);
+            mShader.mTextureTypes.add(texType);
+            return this;
+        }
+
+        public FragmentShader create() {
+            if (mShader.mPerShaderConstants != null) {
+                mBuilder.addConstant(mShader.mPerShaderConstants);
+            }
+            if (mShader.mPerObjConstants != null) {
+                mBuilder.addConstant(mShader.mPerObjConstants);
+            }
+            for (int i = 0; i < mShader.mTextureTypes.size(); i ++) {
+                mBuilder.addTexture(mShader.mTextureTypes.get(i));
+            }
+            for (int i = 0; i < mShader.mShaderTextureTypes.size(); i ++) {
+                mBuilder.addTexture(mShader.mShaderTextureTypes.get(i));
+            }
+
+            mShader.mProgram = mBuilder.create();
+            return mShader;
+        }
+    }
+
+    public ProgramFragment getProgram() {
+        return mProgram;
+    }
+
+    ScriptField_ShaderParam_s getTextureParams() {
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        ArrayList<ScriptField_ShaderParam_s.Item> paramList;
+        paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
+
+        int shaderTextureStart = mTextureTypes.size();
+        for (int i = 0; i < mShaderTextureNames.size(); i ++) {
+            ShaderParam sp = mSourceParams.get(mShaderTextureNames.get(i));
+            if (sp != null && sp instanceof TextureParam) {
+                TextureParam p = (TextureParam)sp;
+                ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
+                paramRS.bufferOffset = shaderTextureStart + i;
+                paramRS.transformTimestamp = 0;
+                paramRS.dataTimestamp = 0;
+                paramRS.data = p.getRSData().getAllocation();
+                paramList.add(paramRS);
+            }
+        }
+
+        ScriptField_ShaderParam_s rsParams = null;
+        int paramCount = paramList.size();
+        if (paramCount != 0) {
+            rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
+            for (int i = 0; i < paramCount; i++) {
+                rsParams.set(paramList.get(i), i, false);
+            }
+            rsParams.copyAll();
+        }
+        return rsParams;
+    }
+
+    ScriptField_FragmentShader_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        ScriptField_FragmentShader_s.Item item = new ScriptField_FragmentShader_s.Item();
+        item.program = mProgram;
+
+        ScriptField_ShaderParam_s texParams = getTextureParams();
+        if (texParams != null) {
+            item.shaderTextureParams = texParams.getAllocation();
+        }
+
+        linkConstants(rs);
+        if (mPerShaderConstants != null) {
+            item.shaderConst = mConstantBuffer;
+            item.shaderConstParams = mConstantBufferParams.getAllocation();
+            mProgram.bindConstants(item.shaderConst, 0);
+        }
+
+        item.objectConstIndex = -1;
+        if (mPerObjConstants != null) {
+            item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
+        }
+
+        mField = new ScriptField_FragmentShader_s(rs, 1);
+        mField.set(item, 0, true);
+        return mField;
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
new file mode 100644
index 0000000..8f5e2e7
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Float3;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class LightBase extends SceneGraphBase {
+    static final int RS_LIGHT_POINT = 0;
+    static final int RS_LIGHT_DIRECTIONAL = 1;
+
+    ScriptField_Light_s mField;
+    ScriptField_Light_s.Item mFieldData;
+    Transform mTransform;
+    Float4 mColor;
+    float mIntensity;
+    public LightBase() {
+        mColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
+        mIntensity = 1.0f;
+    }
+
+    public void setTransform(Transform t) {
+        mTransform = t;
+        updateRSData();
+    }
+
+    public void setColor(float r, float g, float b) {
+        mColor.x = r;
+        mColor.y = g;
+        mColor.z = b;
+        updateRSData();
+    }
+
+    public void setColor(Float3 c) {
+        setColor(c.x, c.y, c.z);
+    }
+
+    public void setIntensity(float i) {
+        mIntensity = i;
+        updateRSData();
+    }
+
+    public void setName(String n) {
+        super.setName(n);
+        updateRSData();
+    }
+
+    protected void updateRSData() {
+        if (mField == null) {
+            return;
+        }
+        RenderScriptGL rs = SceneManager.getRS();
+        mFieldData.transformMatrix = mTransform.getRSData().getAllocation();
+        mFieldData.name = getNameAlloc(rs);
+        mFieldData.color = mColor;
+        mFieldData.intensity = mIntensity;
+
+        initLocalData();
+
+        mField.set(mFieldData, 0, true);
+    }
+
+    abstract void initLocalData();
+
+    ScriptField_Light_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+        if (mField == null) {
+            mField = new ScriptField_Light_s(rs, 1);
+            mFieldData = new ScriptField_Light_s.Item();
+        }
+
+        updateRSData();
+
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
new file mode 100644
index 0000000..6d70bc9
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class MatrixTransform extends Transform {
+
+    Matrix4f mLocalMatrix;
+    public MatrixTransform() {
+        mLocalMatrix = new Matrix4f();
+    }
+
+    public void setMatrix(Matrix4f matrix) {
+        mLocalMatrix = matrix;
+        updateRSData();
+    }
+
+    public Matrix4f getMatrix() {
+        return new Matrix4f(mLocalMatrix.getArray());
+    }
+
+    void initLocalData() {
+        mTransformData.localMat = mLocalMatrix;
+    }
+
+    void updateRSData() {
+        if (mField == null) {
+            return;
+        }
+        mField.set_localMat(0, mLocalMatrix, false);
+        mField.set_isDirty(0, 1, true);
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
new file mode 100644
index 0000000..574bafc
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class PointLight extends LightBase {
+    public PointLight() {
+    }
+
+     void initLocalData() {
+        mFieldData.type = RS_LIGHT_POINT;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
new file mode 100644
index 0000000..02fd69d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.util.Log;
+
+import android.renderscript.*;
+import android.content.res.Resources;
+
+/**
+ * @hide
+ */
+public class RenderPass extends SceneGraphBase {
+
+    TextureRenderTarget mColorTarget;
+    Float4 mClearColor;
+    boolean mShouldClearColor;
+
+    TextureRenderTarget mDepthTarget;
+    float mClearDepth;
+    boolean mShouldClearDepth;
+
+    ArrayList<RenderableBase> mObjectsToDraw;
+
+    Camera mCamera;
+
+    ScriptField_RenderPass_s.Item mRsField;
+
+    public RenderPass() {
+        mObjectsToDraw = new ArrayList<RenderableBase>();
+        mClearColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
+        mShouldClearColor = true;
+        mClearDepth = 1.0f;
+        mShouldClearDepth = true;
+    }
+
+    public void appendRenderable(Renderable d) {
+        mObjectsToDraw.add(d);
+    }
+
+    public void setCamera(Camera c) {
+        mCamera = c;
+    }
+
+    public void setColorTarget(TextureRenderTarget colorTarget) {
+        mColorTarget = colorTarget;
+    }
+    public void setClearColor(Float4 clearColor) {
+        mClearColor = clearColor;
+    }
+    public void setShouldClearColor(boolean shouldClearColor) {
+        mShouldClearColor = shouldClearColor;
+    }
+
+    public void setDepthTarget(TextureRenderTarget depthTarget) {
+        mDepthTarget = depthTarget;
+    }
+    public void setClearDepth(float clearDepth) {
+        mClearDepth = clearDepth;
+    }
+    public void setShouldClearDepth(boolean shouldClearDepth) {
+        mShouldClearDepth = shouldClearDepth;
+    }
+
+    public ArrayList<RenderableBase> getRenderables() {
+        return mObjectsToDraw;
+    }
+
+    ScriptField_RenderPass_s.Item getRsField(RenderScriptGL rs, Resources res) {
+        if (mRsField != null) {
+            return mRsField;
+        }
+
+        mRsField = new ScriptField_RenderPass_s.Item();
+        if (mColorTarget != null) {
+            mRsField.color_target = mColorTarget.getRsData(true).get_texture(0);
+        }
+        if (mColorTarget != null) {
+            mRsField.depth_target = mDepthTarget.getRsData(true).get_texture(0);
+        }
+        mRsField.camera = mCamera != null ? mCamera.getRSData().getAllocation() : null;
+
+        if (mObjectsToDraw.size() != 0) {
+            Allocation drawableData = Allocation.createSized(rs,
+                                                              Element.ALLOCATION(rs),
+                                                              mObjectsToDraw.size());
+            Allocation[] drawableAllocs = new Allocation[mObjectsToDraw.size()];
+            for (int i = 0; i < mObjectsToDraw.size(); i ++) {
+                Renderable dI = (Renderable)mObjectsToDraw.get(i);
+                drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
+            }
+            drawableData.copyFrom(drawableAllocs);
+            mRsField.objects = drawableData;
+        }
+
+        mRsField.clear_color = mClearColor;
+        mRsField.clear_depth = mClearDepth;
+        mRsField.should_clear_color = mShouldClearColor;
+        mRsField.should_clear_depth = mShouldClearDepth;
+        return mRsField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
new file mode 100644
index 0000000..c08a722
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import android.content.res.Resources;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RSRuntimeException;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderState extends SceneGraphBase {
+    VertexShader mVertex;
+    FragmentShader mFragment;
+    ProgramStore mStore;
+    ProgramRaster mRaster;
+
+    ScriptField_RenderState_s mField;
+
+    public RenderState(VertexShader pv,
+                       FragmentShader pf,
+                       ProgramStore ps,
+                       ProgramRaster pr) {
+        mVertex = pv;
+        mFragment = pf;
+        mStore = ps;
+        mRaster = pr;
+    }
+
+    public RenderState(RenderState r) {
+        mVertex = r.mVertex;
+        mFragment = r.mFragment;
+        mStore = r.mStore;
+        mRaster = r.mRaster;
+    }
+
+    public void setProgramVertex(VertexShader pv) {
+        mVertex = pv;
+        updateRSData();
+    }
+
+    public void setProgramFragment(FragmentShader pf) {
+        mFragment = pf;
+        updateRSData();
+    }
+
+    public void setProgramStore(ProgramStore ps) {
+        mStore = ps;
+        updateRSData();
+    }
+
+    public void setProgramRaster(ProgramRaster pr) {
+        mRaster = pr;
+        updateRSData();
+    }
+
+    void updateRSData() {
+        if (mField == null) {
+            return;
+        }
+        ScriptField_RenderState_s.Item item = new ScriptField_RenderState_s.Item();
+        item.pv = mVertex.getRSData().getAllocation();
+        item.pf = mFragment.getRSData().getAllocation();
+        item.ps = mStore;
+        item.pr = mRaster;
+
+        mField.set(item, 0, true);
+    }
+
+    public ScriptField_RenderState_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+
+        mField = new ScriptField_RenderState_s(rs, 1);
+        updateRSData();
+
+        return mField;
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
new file mode 100644
index 0000000..9f7ab41
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.android.scenegraph.Float4Param;
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.ShaderParam;
+import com.android.scenegraph.TransformParam;
+
+import android.content.res.Resources;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Element.DataType;
+import android.renderscript.Matrix4f;
+import android.renderscript.Mesh;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Renderable extends RenderableBase {
+    HashMap<String, ShaderParam> mSourceParams;
+
+    RenderState mRenderState;
+    Transform mTransform;
+
+    String mMeshName;
+    String mMeshIndexName;
+
+    public String mMaterialName;
+
+    ScriptField_Renderable_s mField;
+    ScriptField_Renderable_s.Item mData;
+
+    public Renderable() {
+        mSourceParams = new HashMap<String, ShaderParam>();
+        mData = new ScriptField_Renderable_s.Item();
+    }
+
+    public void setCullType(int cull) {
+        mData.cullType = cull;
+    }
+
+    public void setRenderState(RenderState renderState) {
+        mRenderState = renderState;
+        if (mField != null) {
+            RenderScriptGL rs = SceneManager.getRS();
+            updateFieldItem(rs);
+            mField.set(mData, 0, true);
+        }
+    }
+
+    public void setMesh(Mesh mesh) {
+        mData.mesh = mesh;
+        if (mField != null) {
+            mField.set_mesh(0, mData.mesh, true);
+        }
+    }
+
+    public void setMesh(String mesh, String indexName) {
+        mMeshName = mesh;
+        mMeshIndexName = indexName;
+    }
+
+    public void setMaterialName(String name) {
+        mMaterialName = name;
+    }
+
+    public void setTransform(Transform t) {
+        mTransform = t;
+        if (mField != null) {
+            RenderScriptGL rs = SceneManager.getRS();
+            updateFieldItem(rs);
+            mField.set(mData, 0, true);
+        }
+    }
+
+    public void appendSourceParams(ShaderParam p) {
+        mSourceParams.put(p.getParamName(), p);
+        // Possibly lift this restriction later
+        if (mField != null) {
+            throw new RuntimeException("Can't add source params to objects that are rendering");
+        }
+    }
+
+    public void resolveMeshData(Mesh mesh) {
+        mData.mesh = mesh;
+        if (mData.mesh == null) {
+            Log.v("DRAWABLE: ", "*** NO MESH *** " + mMeshName);
+            return;
+        }
+        int subIndexCount = mData.mesh.getPrimitiveCount();
+        if (subIndexCount == 1 || mMeshIndexName == null) {
+            mData.meshIndex = 0;
+        } else {
+            for (int i = 0; i < subIndexCount; i ++) {
+                if (mData.mesh.getIndexSetAllocation(i).getName().equals(mMeshIndexName)) {
+                    mData.meshIndex = i;
+                    break;
+                }
+            }
+        }
+        if (mField != null) {
+            mField.set(mData, 0, true);
+        }
+    }
+
+    void updateTextures(RenderScriptGL rs) {
+        Iterator<ShaderParam> allParamsIter = mSourceParams.values().iterator();
+        int paramIndex = 0;
+        while (allParamsIter.hasNext()) {
+            ShaderParam sp = allParamsIter.next();
+            if (sp instanceof TextureParam) {
+                TextureParam p = (TextureParam)sp;
+                TextureBase tex = p.getTexture();
+                if (tex != null) {
+                    mData.pf_textures[paramIndex++] = tex.getRsData(false).getAllocation();
+                }
+            }
+        }
+        ProgramFragment pf = mRenderState.mFragment.mProgram;
+        mData.pf_num_textures = pf != null ? Math.min(pf.getTextureCount(), paramIndex) : 0;
+        if (mField != null) {
+            mField.set_pf_textures(0, mData.pf_textures, true);
+            mField.set_pf_num_textures(0, mData.pf_num_textures, true);
+        }
+    }
+
+    public void setVisible(boolean vis) {
+        mData.cullType = vis ? 0 : 2;
+        if (mField != null) {
+            mField.set_cullType(0, mData.cullType, true);
+        }
+    }
+
+    ScriptField_Renderable_s getRsField(RenderScriptGL rs, Resources res) {
+        if (mField != null) {
+            return mField;
+        }
+        updateFieldItem(rs);
+        updateTextures(rs);
+
+        mField = new ScriptField_Renderable_s(rs, 1);
+        mField.set(mData, 0, true);
+
+        return mField;
+    }
+
+    void updateVertexConstants(RenderScriptGL rs) {
+        Allocation pvParams = null, vertexConstants = null;
+        VertexShader pv = mRenderState.mVertex;
+        if (pv != null && pv.getObjectConstants() != null) {
+            vertexConstants = Allocation.createTyped(rs, pv.getObjectConstants());
+            Element vertexConst = vertexConstants.getType().getElement();
+            pvParams = ShaderParam.fillInParams(vertexConst, mSourceParams,
+                                                mTransform).getAllocation();
+        }
+        mData.pv_const = vertexConstants;
+        mData.pv_constParams = pvParams;
+    }
+
+    void updateFragmentConstants(RenderScriptGL rs) {
+        Allocation pfParams = null, fragmentConstants = null;
+        FragmentShader pf = mRenderState.mFragment;
+        if (pf != null && pf.getObjectConstants() != null) {
+            fragmentConstants = Allocation.createTyped(rs, pf.getObjectConstants());
+            Element fragmentConst = fragmentConstants.getType().getElement();
+            pfParams = ShaderParam.fillInParams(fragmentConst, mSourceParams,
+                                                mTransform).getAllocation();
+        }
+        mData.pf_const = fragmentConstants;
+        mData.pf_constParams = pfParams;
+    }
+
+    void updateFieldItem(RenderScriptGL rs) {
+        updateVertexConstants(rs);
+        updateFragmentConstants(rs);
+
+        if (mTransform != null) {
+            mData.transformMatrix = mTransform.getRSData().getAllocation();
+        }
+        mData.name = getNameAlloc(rs);
+        mData.render_state = mRenderState.getRSData().getAllocation();
+        mData.bVolInitialized = 0;
+    }
+}
+
+
+
+
+
diff --git a/libs/rs/rsFifo.cpp b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
similarity index 61%
copy from libs/rs/rsFifo.cpp
copy to tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
index 3d5d8c4..74535dd 100644
--- a/libs/rs/rsFifo.cpp
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
@@ -14,18 +14,26 @@
  * limitations under the License.
  */
 
-#include "rsFifoSocket.h"
-#include "utils/Timers.h"
-#include "utils/StopWatch.h"
+package com.android.scenegraph;
 
-using namespace android;
-using namespace android::renderscript;
+import java.lang.Math;
+import java.util.ArrayList;
 
-Fifo::Fifo() {
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
 
+/**
+ * @hide
+ */
+public class RenderableBase extends SceneGraphBase {
+    public RenderableBase() {
+    }
 }
 
-Fifo::~Fifo() {
 
-}
+
+
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
new file mode 100644
index 0000000..590bbab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderableGroup extends RenderableBase {
+
+    ArrayList<RenderableBase> mChildren;
+
+    public RenderableGroup() {
+        mChildren = new ArrayList<RenderableBase>();
+    }
+
+    public void appendChildren(RenderableBase d) {
+        mChildren.add(d);
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
new file mode 100644
index 0000000..8c09860
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Mesh;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Scene extends SceneGraphBase {
+    private static String TIMER_TAG = "TIMER";
+
+    CompoundTransform mRootTransforms;
+    HashMap<String, Transform> mTransformMap;
+    ArrayList<RenderPass> mRenderPasses;
+    ArrayList<LightBase> mLights;
+    ArrayList<Camera> mCameras;
+    ArrayList<FragmentShader> mFragmentShaders;
+    ArrayList<VertexShader> mVertexShaders;
+    ArrayList<RenderableBase> mRenderables;
+    HashMap<String, RenderableBase> mRenderableMap;
+    ArrayList<Texture2D> mTextures;
+
+    HashMap<String, ArrayList<Renderable> > mRenderableMeshMap;
+
+    // RS Specific stuff
+    ScriptField_SgTransform mTransformRSData;
+
+    RenderScriptGL mRS;
+    Resources mRes;
+
+    ScriptField_RenderPass_s mRenderPassAlloc;
+
+    public Scene() {
+        mRenderPasses = new ArrayList<RenderPass>();
+        mLights = new ArrayList<LightBase>();
+        mCameras = new ArrayList<Camera>();
+        mFragmentShaders = new ArrayList<FragmentShader>();
+        mVertexShaders = new ArrayList<VertexShader>();
+        mRenderables = new ArrayList<RenderableBase>();
+        mRenderableMap = new HashMap<String, RenderableBase>();
+        mRenderableMeshMap = new HashMap<String, ArrayList<Renderable> >();
+        mTextures = new ArrayList<Texture2D>();
+        mRootTransforms = new CompoundTransform();
+        mRootTransforms.setName("_scene_root_");
+        mTransformMap = new HashMap<String, Transform>();
+    }
+
+    public void appendTransform(Transform t) {
+        mRootTransforms.appendChild(t);
+    }
+
+    // temporary
+    public void addToTransformMap(Transform t) {
+        mTransformMap.put(t.getName(), t);
+    }
+
+    public Transform getTransformByName(String name) {
+        return mTransformMap.get(name);
+    }
+
+    public void appendRenderPass(RenderPass p) {
+        mRenderPasses.add(p);
+    }
+
+    public void clearRenderPasses() {
+        mRenderPasses.clear();
+    }
+
+    public void appendLight(LightBase l) {
+        mLights.add(l);
+    }
+
+    public void appendCamera(Camera c) {
+        mCameras.add(c);
+    }
+
+    public void appendShader(FragmentShader f) {
+        mFragmentShaders.add(f);
+    }
+
+    public void appendShader(VertexShader v) {
+        mVertexShaders.add(v);
+    }
+
+    public ArrayList<Camera> getCameras() {
+        return mCameras;
+    }
+
+    public ArrayList<LightBase> getLights() {
+        return mLights;
+    }
+
+    public void appendRenderable(RenderableBase d) {
+        mRenderables.add(d);
+        mRenderableMap.put(d.getName(), d);
+    }
+
+    public ArrayList<RenderableBase> getRenderables() {
+        return mRenderables;
+    }
+
+    public RenderableBase getRenderableByName(String name) {
+        return mRenderableMap.get(name);
+    }
+
+    public void appendTextures(Texture2D tex) {
+        mTextures.add(tex);
+    }
+
+    public void assignRenderStateToMaterial(RenderState renderState, String regex) {
+        Pattern pattern = Pattern.compile(regex);
+        int numRenderables = mRenderables.size();
+        for (int i = 0; i < numRenderables; i ++) {
+            Renderable shape = (Renderable)mRenderables.get(i);
+            Matcher m = pattern.matcher(shape.mMaterialName);
+            if (m.find()) {
+                shape.setRenderState(renderState);
+            }
+        }
+    }
+
+    public void assignRenderState(RenderState renderState) {
+        int numRenderables = mRenderables.size();
+        for (int i = 0; i < numRenderables; i ++) {
+            Renderable shape = (Renderable)mRenderables.get(i);
+            shape.setRenderState(renderState);
+        }
+    }
+
+    public void meshLoaded(Mesh m) {
+        ArrayList<Renderable> entries = mRenderableMeshMap.get(m.getName());
+        int numEntries = entries.size();
+        for (int i = 0; i < numEntries; i++) {
+            Renderable d = entries.get(i);
+            d.resolveMeshData(m);
+        }
+    }
+
+    void addToMeshMap(Renderable d) {
+        ArrayList<Renderable> entries = mRenderableMeshMap.get(d.mMeshName);
+        if (entries == null) {
+            entries = new ArrayList<Renderable>();
+            mRenderableMeshMap.put(d.mMeshName, entries);
+        }
+        entries.add(d);
+    }
+
+    public void destroyRS() {
+        SceneManager sceneManager = SceneManager.getInstance();
+        mTransformRSData = null;
+        sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
+        sceneManager.mRenderLoop.set_gRenderableObjects(null);
+        mRenderPassAlloc = null;
+        sceneManager.mRenderLoop.set_gRenderPasses(null);
+        sceneManager.mRenderLoop.bind_gFrontToBack(null);
+        sceneManager.mRenderLoop.bind_gBackToFront(null);
+        sceneManager.mRenderLoop.set_gCameras(null);
+
+        mTransformMap = null;
+        mRenderPasses = null;
+        mLights = null;
+        mCameras = null;
+        mRenderables = null;
+        mRenderableMap = null;
+        mTextures = null;
+        mRenderableMeshMap = null;
+        mRootTransforms = null;
+    }
+
+    public void initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager) {
+        if (mRenderPasses.size() != 0) {
+            mRenderPassAlloc = new ScriptField_RenderPass_s(mRS, mRenderPasses.size());
+            for (int i = 0; i < mRenderPasses.size(); i ++) {
+                mRenderPassAlloc.set(mRenderPasses.get(i).getRsField(mRS, mRes), i, false);
+            }
+            mRenderPassAlloc.copyAll();
+            sceneManager.mRenderLoop.set_gRenderPasses(mRenderPassAlloc.getAllocation());
+        }
+    }
+
+    private void addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
+        Allocation drawableData = Allocation.createSized(rs,
+                                                         Element.ALLOCATION(rs),
+                                                         mRenderables.size());
+        Allocation[] drawableAllocs = new Allocation[mRenderables.size()];
+        for (int i = 0; i < mRenderables.size(); i ++) {
+            Renderable dI = (Renderable)mRenderables.get(i);
+            addToMeshMap(dI);
+            drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
+        }
+        drawableData.copyFrom(drawableAllocs);
+        sceneManager.mRenderLoop.set_gRenderableObjects(drawableData);
+
+        initRenderPassRS(rs, sceneManager);
+    }
+
+    private void addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
+        Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs),
+                                                       mVertexShaders.size());
+        Allocation[] shaderAllocs = new Allocation[mVertexShaders.size()];
+        for (int i = 0; i < mVertexShaders.size(); i ++) {
+            VertexShader sI = mVertexShaders.get(i);
+            shaderAllocs[i] = sI.getRSData().getAllocation();
+        }
+        shaderData.copyFrom(shaderAllocs);
+        sceneManager.mRenderLoop.set_gVertexShaders(shaderData);
+
+        shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), mFragmentShaders.size());
+        shaderAllocs = new Allocation[mFragmentShaders.size()];
+        for (int i = 0; i < mFragmentShaders.size(); i ++) {
+            FragmentShader sI = mFragmentShaders.get(i);
+            shaderAllocs[i] = sI.getRSData().getAllocation();
+        }
+        shaderData.copyFrom(shaderAllocs);
+        sceneManager.mRenderLoop.set_gFragmentShaders(shaderData);
+    }
+
+    public void initRS() {
+        SceneManager sceneManager = SceneManager.getInstance();
+        mRS = SceneManager.getRS();
+        mRes = SceneManager.getRes();
+        long start = System.currentTimeMillis();
+        mTransformRSData = mRootTransforms.getRSData();
+        long end = System.currentTimeMillis();
+        Log.v(TIMER_TAG, "Transform init time: " + (end - start));
+
+        start = System.currentTimeMillis();
+
+        sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
+        end = System.currentTimeMillis();
+        Log.v(TIMER_TAG, "Script init time: " + (end - start));
+
+        start = System.currentTimeMillis();
+        addDrawables(mRS, mRes, sceneManager);
+        end = System.currentTimeMillis();
+        Log.v(TIMER_TAG, "Renderable init time: " + (end - start));
+
+        addShaders(mRS, mRes, sceneManager);
+
+        Allocation opaqueBuffer = null;
+        if (mRenderables.size() > 0) {
+            opaqueBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
+        }
+        Allocation transparentBuffer = null;
+        if (mRenderables.size() > 0) {
+            transparentBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
+        }
+
+        sceneManager.mRenderLoop.bind_gFrontToBack(opaqueBuffer);
+        sceneManager.mRenderLoop.bind_gBackToFront(transparentBuffer);
+
+        if (mCameras.size() > 0) {
+            Allocation cameraData;
+            cameraData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mCameras.size());
+            Allocation[] cameraAllocs = new Allocation[mCameras.size()];
+            for (int i = 0; i < mCameras.size(); i ++) {
+                cameraAllocs[i] = mCameras.get(i).getRSData().getAllocation();
+            }
+            cameraData.copyFrom(cameraAllocs);
+            sceneManager.mRenderLoop.set_gCameras(cameraData);
+        }
+
+        if (mLights.size() > 0) {
+            Allocation lightData = Allocation.createSized(mRS,
+                                                          Element.ALLOCATION(mRS),
+                                                          mLights.size());
+            Allocation[] lightAllocs = new Allocation[mLights.size()];
+            for (int i = 0; i < mLights.size(); i ++) {
+                lightAllocs[i] = mLights.get(i).getRSData().getAllocation();
+            }
+            lightData.copyFrom(lightAllocs);
+            sceneManager.mRenderLoop.set_gLights(lightData);
+        }
+    }
+}
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
new file mode 100644
index 0000000..412ffbf
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RSRuntimeException;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class SceneGraphBase {
+    String mName;
+    Allocation mNameAlloc;
+    public void setName(String n) {
+        mName = n;
+        mNameAlloc = null;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    Allocation getNameAlloc(RenderScriptGL rs) {
+        if (mNameAlloc == null)  {
+            mNameAlloc = SceneManager.getStringAsAllocation(rs, getName());
+        }
+        return mNameAlloc;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
new file mode 100644
index 0000000..f77f483
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.android.scenegraph.Camera;
+import com.android.scenegraph.MatrixTransform;
+import com.android.scenegraph.Scene;
+import com.android.testapp.R;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Mesh;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Type.Builder;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+/**
+ * @hide
+ */
+public class SceneManager extends SceneGraphBase {
+
+    HashMap<String, Allocation> mAllocationMap;
+
+    ScriptC_render mRenderLoop;
+    ScriptC mCameraScript;
+    ScriptC mLightScript;
+    ScriptC mObjectParamsScript;
+    ScriptC mFragmentParamsScript;
+    ScriptC mVertexParamsScript;
+    ScriptC mCullScript;
+    ScriptC_transform mTransformScript;
+    ScriptC_export mExportScript;
+
+    RenderScriptGL mRS;
+    Resources mRes;
+    Mesh mQuad;
+    int mWidth;
+    int mHeight;
+
+    Scene mActiveScene;
+    private static SceneManager sSceneManager;
+
+    private Allocation sDefault2D;
+    private Allocation sDefaultCube;
+
+    private static Allocation getDefault(boolean isCube) {
+        final int dimension = 4;
+        final int bytesPerPixel = 4;
+        int arraySize = dimension * dimension * bytesPerPixel;
+
+        RenderScriptGL rs = sSceneManager.mRS;
+        Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
+        b.setX(dimension).setY(dimension);
+        if (isCube) {
+            b.setFaces(true);
+            arraySize *= 6;
+        }
+        Type bitmapType = b.create();
+
+        Allocation.MipmapControl mip = Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE;
+        int usage =  Allocation.USAGE_GRAPHICS_TEXTURE;
+        Allocation defaultImage = Allocation.createTyped(rs, bitmapType, mip, usage);
+
+        byte imageData[] = new byte[arraySize];
+        defaultImage.copyFrom(imageData);
+        return defaultImage;
+    }
+
+    static Allocation getDefaultTex2D() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        if (sSceneManager.sDefault2D == null) {
+            sSceneManager.sDefault2D = getDefault(false);
+        }
+        return sSceneManager.sDefault2D;
+    }
+
+    static Allocation getDefaultTexCube() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        if (sSceneManager.sDefaultCube == null) {
+            sSceneManager.sDefaultCube = getDefault(true);
+        }
+        return sSceneManager.sDefaultCube;
+    }
+
+    public static boolean isSDCardPath(String path) {
+        int sdCardIndex = path.indexOf("sdcard/");
+        // We are looking for /sdcard/ or sdcard/
+        if (sdCardIndex == 0 || sdCardIndex == 1) {
+            return true;
+        }
+        sdCardIndex = path.indexOf("mnt/sdcard/");
+        if (sdCardIndex == 0 || sdCardIndex == 1) {
+            return true;
+        }
+        return false;
+    }
+
+    static Bitmap loadBitmap(String name, Resources res) {
+        InputStream is = null;
+        boolean loadFromSD = isSDCardPath(name);
+        try {
+            if (!loadFromSD) {
+                is = res.getAssets().open(name);
+            } else {
+                File f = new File(name);
+                is = new BufferedInputStream(new FileInputStream(f));
+            }
+        } catch (IOException e) {
+            Log.e("ImageLoaderTask", " Message: " + e.getMessage());
+            return null;
+        }
+
+        Bitmap b = BitmapFactory.decodeStream(is);
+        try {
+            is.close();
+        } catch (IOException e) {
+            Log.e("ImageLoaderTask", " Message: " + e.getMessage());
+        }
+        return b;
+    }
+
+    public static Allocation loadCubemap(String name, RenderScriptGL rs, Resources res) {
+        Bitmap b = loadBitmap(name, res);
+        if (b == null) {
+            return null;
+        }
+        return Allocation.createCubemapFromBitmap(rs, b,
+                                                  MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+                                                  Allocation.USAGE_GRAPHICS_TEXTURE);
+    }
+
+    public static Allocation loadTexture2D(String name, RenderScriptGL rs, Resources res) {
+        Bitmap b = loadBitmap(name, res);
+        if (b == null) {
+            return null;
+        }
+        return Allocation.createFromBitmap(rs, b,
+                                           Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+                                           Allocation.USAGE_GRAPHICS_TEXTURE);
+    }
+
+    public static ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+        ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+        builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
+        builder.setDitherEnabled(false);
+        builder.setDepthMaskEnabled(false);
+        return builder.create();
+    }
+
+    static Allocation getStringAsAllocation(RenderScript rs, String str) {
+        if (str == null) {
+            return null;
+        }
+        if (str.length() == 0) {
+            return null;
+        }
+        byte[] allocArray = null;
+        byte[] nullChar = new byte[1];
+        nullChar[0] = 0;
+        try {
+            allocArray = str.getBytes("UTF-8");
+            Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
+                                                      allocArray.length + 1,
+                                                      Allocation.USAGE_SCRIPT);
+            alloc.copy1DRangeFrom(0, allocArray.length, allocArray);
+            alloc.copy1DRangeFrom(allocArray.length, 1, nullChar);
+            return alloc;
+        }
+        catch (Exception e) {
+            throw new RSRuntimeException("Could not convert string to utf-8.");
+        }
+    }
+
+    static Allocation getCachedAlloc(String str) {
+        if (sSceneManager == null) {
+            throw new RuntimeException("Scene manager not initialized");
+        }
+        return sSceneManager.mAllocationMap.get(str);
+    }
+
+    static void cacheAlloc(String str, Allocation alloc) {
+        if (sSceneManager == null) {
+            throw new RuntimeException("Scene manager not initialized");
+        }
+        sSceneManager.mAllocationMap.put(str, alloc);
+    }
+
+    public static class SceneLoadedCallback implements Runnable {
+        public Scene mLoadedScene;
+        public String mName;
+        public void run() {
+        }
+    }
+
+    public Scene getActiveScene() {
+        return mActiveScene;
+    }
+
+    public void setActiveScene(Scene s) {
+        mActiveScene = s;
+
+        // Do some sanity checking
+        if (mActiveScene.getCameras().size() == 0) {
+            Matrix4f camPos = new Matrix4f();
+            camPos.translate(0, 0, 10);
+            MatrixTransform cameraTransform = new MatrixTransform();
+            cameraTransform.setName("_DefaultCameraTransform");
+            cameraTransform.setMatrix(camPos);
+            mActiveScene.appendTransform(cameraTransform);
+            Camera cam = new Camera();
+            cam.setName("_DefaultCamera");
+            cam.setTransform(cameraTransform);
+            mActiveScene.appendCamera(cam);
+        }
+    }
+
+    static RenderScriptGL getRS() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        return sSceneManager.mRS;
+    }
+
+    static Resources getRes() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        return sSceneManager.mRes;
+    }
+
+    public static SceneManager getInstance() {
+        if (sSceneManager == null) {
+            sSceneManager = new SceneManager();
+        }
+        return sSceneManager;
+    }
+
+    protected SceneManager() {
+    }
+
+    public void loadModel(String name, SceneLoadedCallback cb) {
+        ColladaScene scene = new ColladaScene(name, cb);
+        scene.init(mRS, mRes);
+    }
+
+    public Mesh getScreenAlignedQuad() {
+        if (mQuad != null) {
+            return mQuad;
+        }
+
+        Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
+                                           3, Mesh.TriangleMeshBuilder.TEXTURE_0);
+
+        tmb.setTexture(0.0f, 1.0f);
+        tmb.addVertex(-1.0f, 1.0f, 1.0f);
+
+        tmb.setTexture(0.0f, 0.0f);
+        tmb.addVertex(-1.0f, -1.0f, 1.0f);
+
+        tmb.setTexture(1.0f, 0.0f);
+        tmb.addVertex(1.0f, -1.0f, 1.0f);
+
+        tmb.setTexture(1.0f, 1.0f);
+        tmb.addVertex(1.0f, 1.0f, 1.0f);
+
+        tmb.addTriangle(0, 1, 2);
+        tmb.addTriangle(2, 3, 0);
+
+        mQuad = tmb.create(true);
+        return mQuad;
+    }
+
+    public Renderable getRenderableQuad(String name, RenderState state) {
+        Renderable quad = new Renderable();
+        quad.setTransform(new MatrixTransform());
+        quad.setMesh(getScreenAlignedQuad());
+        quad.setName(name);
+        quad.setRenderState(state);
+        quad.setCullType(1);
+        return quad;
+    }
+
+    public void initRS(RenderScriptGL rs, Resources res, int w, int h) {
+        mRS = rs;
+        mRes = res;
+        mAllocationMap = new HashMap<String, Allocation>();
+
+        mExportScript = new ScriptC_export(rs, res, R.raw.export);
+
+        mTransformScript = new ScriptC_transform(rs, res, R.raw.transform);
+        mTransformScript.set_gTransformScript(mTransformScript);
+
+        mCameraScript = new ScriptC_camera(rs, res, R.raw.camera);
+        mLightScript = new ScriptC_light(rs, res, R.raw.light);
+        mObjectParamsScript = new ScriptC_object_params(rs, res, R.raw.object_params);
+        mFragmentParamsScript = new ScriptC_object_params(rs, res, R.raw.fragment_params);
+        mVertexParamsScript = new ScriptC_object_params(rs, res, R.raw.vertex_params);
+        mCullScript = new ScriptC_cull(rs, res, R.raw.cull);
+
+        mRenderLoop = new ScriptC_render(rs, res, R.raw.render);
+        mRenderLoop.set_gTransformScript(mTransformScript);
+        mRenderLoop.set_gCameraScript(mCameraScript);
+        mRenderLoop.set_gLightScript(mLightScript);
+        mRenderLoop.set_gObjectParamsScript(mObjectParamsScript);
+        mRenderLoop.set_gFragmentParamsScript(mFragmentParamsScript);
+        mRenderLoop.set_gVertexParamsScript(mVertexParamsScript);
+        mRenderLoop.set_gCullScript(mCullScript);
+
+        mRenderLoop.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
+    }
+
+    public ScriptC getRenderLoop() {
+        return mRenderLoop;
+    }
+}
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
new file mode 100644
index 0000000..4975114
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.android.scenegraph.SceneGraphBase;
+import com.android.scenegraph.ShaderParam;
+
+import android.renderscript.*;
+import android.renderscript.ProgramFragment.Builder;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class Shader extends SceneGraphBase {
+    protected Type mPerObjConstants;
+    protected Type mPerShaderConstants;
+
+    protected HashMap<String, ShaderParam> mSourceParams;
+    protected ArrayList<String> mShaderTextureNames;
+    protected ArrayList<Program.TextureType > mShaderTextureTypes;
+    protected ArrayList<String> mTextureNames;
+    protected ArrayList<Program.TextureType > mTextureTypes;
+
+    protected Allocation mConstantBuffer;
+    protected ScriptField_ShaderParam_s mConstantBufferParams;
+
+    public Shader() {
+        mSourceParams = new HashMap<String, ShaderParam>();
+        mShaderTextureNames = new ArrayList<String>();
+        mShaderTextureTypes = new ArrayList<Program.TextureType>();
+        mTextureNames = new ArrayList<String>();
+        mTextureTypes = new ArrayList<Program.TextureType>();
+    }
+
+    public void appendSourceParams(ShaderParam p) {
+        mSourceParams.put(p.getParamName(), p);
+    }
+
+    public Type getObjectConstants() {
+        return mPerObjConstants;
+    }
+
+    public Type getShaderConstants() {
+        return mPerObjConstants;
+    }
+
+    void linkConstants(RenderScriptGL rs) {
+        if (mPerShaderConstants == null) {
+            return;
+        }
+
+        Element constElem = mPerShaderConstants.getElement();
+        mConstantBufferParams  = ShaderParam.fillInParams(constElem, mSourceParams, null);
+
+        mConstantBuffer = Allocation.createTyped(rs, mPerShaderConstants);
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
new file mode 100644
index 0000000..8dea535
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.Transform;
+
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class ShaderParam extends SceneGraphBase {
+
+    static final String cameraPos        = "cameraPos";
+    static final String cameraDir        = "cameraDir";
+
+    static final String lightColor       = "lightColor";
+    static final String lightPos         = "lightPos";
+    static final String lightDir         = "lightDir";
+
+    static final String view             = "view";
+    static final String proj             = "proj";
+    static final String viewProj         = "viewProj";
+    static final String model            = "model";
+    static final String modelView        = "modelView";
+    static final String modelViewProj    = "modelViewProj";
+
+    static final long sMaxTimeStamp = 0xffffffffL;
+
+    ScriptField_ShaderParamData_s.Item mData;
+    ScriptField_ShaderParamData_s mField;
+
+    String mParamName;
+    Camera mCamera;
+
+    static ScriptField_ShaderParam_s fillInParams(Element constantElem,
+                                                  HashMap<String, ShaderParam> sourceParams,
+                                                  Transform transform) {
+        RenderScriptGL rs = SceneManager.getRS();
+        ArrayList<ScriptField_ShaderParam_s.Item> paramList;
+        paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
+
+        int subElemCount = constantElem.getSubElementCount();
+        for (int i = 0; i < subElemCount; i ++) {
+            String inputName = constantElem.getSubElementName(i);
+            int offset = constantElem.getSubElementOffsetBytes(i);
+
+            ShaderParam matchingParam = sourceParams.get(inputName);
+            Element subElem = constantElem.getSubElement(i);
+            // Make one if it's not there
+            if (matchingParam == null) {
+                if (subElem.getDataType() == Element.DataType.FLOAT_32) {
+                    matchingParam = new Float4Param(inputName);
+                } else if (subElem.getDataType() == Element.DataType.MATRIX_4X4) {
+                    TransformParam trParam = new TransformParam(inputName);
+                    trParam.setTransform(transform);
+                    matchingParam = trParam;
+                }
+            }
+            ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
+            paramRS.bufferOffset = offset;
+            paramRS.transformTimestamp = 0;
+            paramRS.dataTimestamp = 0;
+            paramRS.data = matchingParam.getRSData().getAllocation();
+            if (subElem.getDataType() == Element.DataType.FLOAT_32) {
+                paramRS.float_vecSize = subElem.getVectorSize();
+            }
+
+            paramList.add(paramRS);
+        }
+
+        ScriptField_ShaderParam_s rsParams = null;
+        int paramCount = paramList.size();
+        if (paramCount != 0) {
+            rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
+            for (int i = 0; i < paramCount; i++) {
+                rsParams.set(paramList.get(i), i, false);
+            }
+            rsParams.copyAll();
+        }
+        return rsParams;
+    }
+
+    public ShaderParam(String name) {
+        mParamName = name;
+        mData = new ScriptField_ShaderParamData_s.Item();
+    }
+
+    public String getParamName() {
+        return mParamName;
+    }
+
+    public void setCamera(Camera c) {
+        mCamera = c;
+        if (mField != null) {
+            mData.camera = mCamera.getRSData().getAllocation();
+            mField.set_camera(0, mData.camera, true);
+        }
+    }
+
+    protected void incTimestamp() {
+        if (mField != null) {
+            mData.timestamp ++;
+            mData.timestamp %= sMaxTimeStamp;
+            mField.set_timestamp(0, mData.timestamp, true);
+        }
+    }
+
+    abstract void initLocalData();
+
+    public ScriptField_ShaderParamData_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        mField = new ScriptField_ShaderParamData_s(rs, 1);
+
+        if (mParamName != null) {
+            mData.paramName = SceneManager.getCachedAlloc(mParamName);
+            if (mData.paramName == null) {
+                mData.paramName = SceneManager.getStringAsAllocation(rs, mParamName);
+                SceneManager.cacheAlloc(mParamName, mData.paramName);
+            }
+        }
+        initLocalData();
+        mData.timestamp = 1;
+
+        mField.set(mData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
new file mode 100644
index 0000000..8fae9d9
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Texture2D extends TextureBase {
+    String mFileName;
+    String mFileDir;
+
+    public Texture2D() {
+        super(ScriptC_export.const_TextureType_TEXTURE_2D);
+    }
+
+    public Texture2D(Allocation tex) {
+        super(ScriptC_export.const_TextureType_TEXTURE_2D);
+        setTexture(tex);
+    }
+
+    public void setFileDir(String dir) {
+        mFileDir = dir;
+    }
+
+    public void setFileName(String file) {
+        mFileName = file;
+    }
+
+    public String getFileName() {
+        return mFileName;
+    }
+
+    public void setTexture(Allocation tex) {
+        mData.texture = tex != null ? tex : SceneManager.getDefaultTex2D();
+        if (mField != null) {
+            mField.set_texture(0, mData.texture, true);
+        }
+    }
+
+    void load() {
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
+        setTexture(SceneManager.loadTexture2D(mFileDir + shortName, rs, res));
+    }
+
+    ScriptField_Texture_s getRsData(boolean loadNow) {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        mField = new ScriptField_Texture_s(rs, 1);
+
+        if (loadNow) {
+            load();
+        } else {
+            mData.texture = SceneManager.getDefaultTex2D();
+            new SingleImageLoaderTask().execute(this);
+        }
+
+        mField.set(mData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
new file mode 100644
index 0000000..ba49d4e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+import android.os.AsyncTask;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class TextureBase extends SceneGraphBase {
+
+    class SingleImageLoaderTask extends AsyncTask<TextureBase, Void, Boolean> {
+        protected Boolean doInBackground(TextureBase... objects) {
+            TextureBase tex = objects[0];
+            tex.load();
+            return new Boolean(true);
+        }
+        protected void onPostExecute(Boolean result) {
+        }
+    }
+
+    ScriptField_Texture_s.Item mData;
+    ScriptField_Texture_s mField;
+    TextureBase(int type) {
+        mData = new ScriptField_Texture_s.Item();
+        mData.type = type;
+    }
+
+    protected Allocation mRsTexture;
+    abstract ScriptField_Texture_s getRsData(boolean loadNow);
+    abstract void load();
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
new file mode 100644
index 0000000..12c81c2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureCube extends TextureBase {
+    String mFileName;
+    String mFileDir;
+
+    public TextureCube() {
+        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+    }
+
+    public TextureCube(Allocation tex) {
+        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+        setTexture(tex);
+    }
+
+    public TextureCube(String dir, String file) {
+        super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+        setFileDir(dir);
+        setFileName(file);
+    }
+
+    public void setFileDir(String dir) {
+        mFileDir = dir;
+    }
+
+    public void setFileName(String file) {
+        mFileName = file;
+    }
+
+    public String getFileName() {
+        return mFileName;
+    }
+
+    public void setTexture(Allocation tex) {
+        mData.texture = tex != null ? tex : SceneManager.getDefaultTexCube();
+        if (mField != null) {
+            mField.set_texture(0, mData.texture, true);
+        }
+    }
+
+    void load() {
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
+        setTexture(SceneManager.loadCubemap(mFileDir + shortName, rs, res));
+    }
+
+    ScriptField_Texture_s getRsData(boolean loadNow) {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        mField = new ScriptField_Texture_s(rs, 1);
+
+        if (loadNow) {
+            load();
+        } else {
+            mData.texture = SceneManager.getDefaultTexCube();
+            new SingleImageLoaderTask().execute(this);
+        }
+
+        mField.set(mData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
new file mode 100644
index 0000000..e656ed2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.graphics.Camera;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureParam extends ShaderParam {
+
+    TextureBase mTexture;
+
+    public TextureParam(String name) {
+        super(name);
+    }
+
+    public TextureParam(String name, TextureBase t) {
+        super(name);
+        setTexture(t);
+    }
+
+    public void setTexture(TextureBase t) {
+        mTexture = t;
+    }
+
+    public TextureBase getTexture() {
+        return mTexture;
+    }
+
+    void initLocalData() {
+        mData.type = ScriptC_export.const_ShaderParam_TEXTURE;
+        if (mTexture != null) {
+            mData.texture = mTexture.getRsData(false).getAllocation();
+        }
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
new file mode 100644
index 0000000..6aa29a5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureRenderTarget extends TextureBase {
+    public TextureRenderTarget() {
+        super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
+    }
+
+    public TextureRenderTarget(Allocation tex) {
+        super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
+        setTexture(tex);
+    }
+
+    public void setTexture(Allocation tex) {
+        mData.texture = tex;
+        if (mField != null) {
+            mField.set_texture(0, mData.texture, true);
+        }
+    }
+
+    void load() {
+    }
+
+    ScriptField_Texture_s getRsData(boolean loadNow) {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+
+        mField = new ScriptField_Texture_s(rs, 1);
+        mField.set(mData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
new file mode 100644
index 0000000..8180bd0
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.*;
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class Transform extends SceneGraphBase {
+    Transform mParent;
+    ArrayList<Transform> mChildren;
+
+    ScriptField_SgTransform mField;
+    ScriptField_SgTransform.Item mTransformData;
+
+    public Transform() {
+        mChildren = new ArrayList<Transform>();
+        mParent = null;
+    }
+
+    public void appendChild(Transform t) {
+        mChildren.add(t);
+        t.mParent = this;
+        updateRSChildData(true);
+    }
+
+    abstract void initLocalData();
+
+    void updateRSChildData(boolean copyData) {
+        if (mField == null) {
+            return;
+        }
+        RenderScriptGL rs = SceneManager.getRS();
+        if (mChildren.size() != 0) {
+            Allocation childRSData = Allocation.createSized(rs, Element.ALLOCATION(rs),
+                                                            mChildren.size());
+            mTransformData.children = childRSData;
+
+            Allocation[] childrenAllocs = new Allocation[mChildren.size()];
+            for (int i = 0; i < mChildren.size(); i ++) {
+                Transform child = mChildren.get(i);
+                childrenAllocs[i] = child.getRSData().getAllocation();
+            }
+            childRSData.copyFrom(childrenAllocs);
+        }
+        if (copyData) {
+            mField.set(mTransformData, 0, true);
+        }
+    }
+
+    ScriptField_SgTransform getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        if (rs == null) {
+            return null;
+        }
+        mField = new ScriptField_SgTransform(rs, 1);
+
+        mTransformData = new ScriptField_SgTransform.Item();
+        mTransformData.name = getNameAlloc(rs);
+        mTransformData.isDirty = 1;
+        mTransformData.timestamp = 1;
+
+        initLocalData();
+        updateRSChildData(false);
+
+        mField.set(mTransformData, 0, true);
+        return mField;
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
new file mode 100644
index 0000000..d120d5d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TransformParam extends ShaderParam {
+
+    Transform mTransform;
+    LightBase mLight;
+
+    public TransformParam(String name) {
+        super(name);
+    }
+
+    public void setTransform(Transform t) {
+        mTransform = t;
+        if (mField != null && mTransform != null) {
+            mData.transform = mTransform.getRSData().getAllocation();
+        }
+        incTimestamp();
+    }
+
+    int getTypeFromName() {
+        int paramType = ScriptC_export.const_ShaderParam_TRANSFORM_DATA;
+        if (mParamName.equalsIgnoreCase(view)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW;
+        } else if(mParamName.equalsIgnoreCase(proj)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_PROJ;
+        } else if(mParamName.equalsIgnoreCase(viewProj)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW_PROJ;
+        } else if(mParamName.equalsIgnoreCase(model)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL;
+        } else if(mParamName.equalsIgnoreCase(modelView)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW;
+        } else if(mParamName.equalsIgnoreCase(modelViewProj)) {
+            paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW_PROJ;
+        }
+        return paramType;
+    }
+
+    void initLocalData() {
+        mData.type = getTypeFromName();
+        if (mTransform != null) {
+            mData.transform = mTransform.getRSData().getAllocation();
+        }
+        if (mCamera != null) {
+            mData.camera = mCamera.getRSData().getAllocation();
+        }
+        if (mLight != null) {
+            mData.light = mLight.getRSData().getAllocation();
+        }
+    }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
new file mode 100644
index 0000000..f7d0e6d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class VertexShader extends Shader {
+    ProgramVertex mProgram;
+    ScriptField_VertexShader_s mField;
+
+    public static class Builder {
+        VertexShader mShader;
+        ProgramVertex.Builder mBuilder;
+
+        public Builder(RenderScriptGL rs) {
+            mShader = new VertexShader();
+            mBuilder = new ProgramVertex.Builder(rs);
+        }
+
+        public Builder setShader(Resources resources, int resourceID) {
+            mBuilder.setShader(resources, resourceID);
+            return this;
+        }
+
+        public Builder setObjectConst(Type type) {
+            mShader.mPerObjConstants = type;
+            return this;
+        }
+
+        public Builder setShaderConst(Type type) {
+            mShader.mPerShaderConstants = type;
+            return this;
+        }
+
+        public Builder addInput(Element e) {
+            mBuilder.addInput(e);
+            return this;
+        }
+
+        public VertexShader create() {
+            if (mShader.mPerShaderConstants != null) {
+                mBuilder.addConstant(mShader.mPerShaderConstants);
+            }
+            if (mShader.mPerObjConstants != null) {
+                mBuilder.addConstant(mShader.mPerObjConstants);
+            }
+            mShader.mProgram = mBuilder.create();
+            return mShader;
+        }
+    }
+
+    public ProgramVertex getProgram() {
+        return mProgram;
+    }
+
+    ScriptField_VertexShader_s getRSData() {
+        if (mField != null) {
+            return mField;
+        }
+
+        RenderScriptGL rs = SceneManager.getRS();
+        Resources res = SceneManager.getRes();
+        if (rs == null || res == null) {
+            return null;
+        }
+
+        ScriptField_VertexShader_s.Item item = new ScriptField_VertexShader_s.Item();
+        item.program = mProgram;
+
+        linkConstants(rs);
+        if (mPerShaderConstants != null) {
+            item.shaderConst = mConstantBuffer;
+            item.shaderConstParams = mConstantBufferParams.getAllocation();
+            mProgram.bindConstants(item.shaderConst, 0);
+        }
+
+        item.objectConstIndex = -1;
+        if (mPerObjConstants != null) {
+            item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
+        }
+
+        mField = new ScriptField_VertexShader_s(rs, 1);
+        mField.set(item, 0, true);
+        return mField;
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
new file mode 100644
index 0000000..dc0a885
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
@@ -0,0 +1,66 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+//#define DEBUG_CAMERA
+#include "scenegraph_objects.rsh"
+
+void root(const rs_allocation *v_in, rs_allocation *v_out, const float *usrData) {
+
+    SgCamera *cam = (SgCamera *)rsGetElementAt(*v_in, 0);
+    float aspect = *usrData;
+    if (cam->aspect != aspect) {
+        cam->isDirty = 1;
+        cam->aspect = aspect;
+    }
+    if (cam->isDirty) {
+        rsMatrixLoadPerspective(&cam->proj, cam->horizontalFOV, cam->aspect, cam->near, cam->far);
+    }
+
+    const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
+    //rsDebug("Camera stamp", cam->transformTimestamp);
+    //rsDebug("Transform stamp", camTransform->timestamp);
+    if (camTransform->timestamp != cam->transformTimestamp || cam->isDirty) {
+        cam->isDirty = 1;
+        rs_matrix4x4 camPosMatrix;
+        rsMatrixLoad(&camPosMatrix, &camTransform->globalMat);
+        float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
+        cam->position = rsMatrixMultiply(&camPosMatrix, zero);
+
+        rsMatrixInverse(&camPosMatrix);
+        rsMatrixLoad(&cam->view, &camPosMatrix);
+
+        rsMatrixLoad(&cam->viewProj, &cam->proj);
+        rsMatrixMultiply(&cam->viewProj, &cam->view);
+
+        rsExtractFrustumPlanes(&cam->viewProj,
+                               &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+                               &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+                               &cam->frustumPlanes[3], &cam->frustumPlanes[4]);
+    }
+
+    if (cam->isDirty) {
+        cam->timestamp ++;
+    }
+
+    cam->isDirty = 0;
+    cam->transformTimestamp = camTransform->timestamp;
+
+#ifdef DEBUG_CAMERA
+    printCameraInfo(cam);
+#endif //DEBUG_CAMERA
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
new file mode 100644
index 0000000..024e026
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
@@ -0,0 +1,86 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+static void getTransformedSphere(SgRenderable *obj) {
+    obj->worldBoundingSphere = obj->boundingSphere;
+    obj->worldBoundingSphere.w = 1.0f;
+    const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
+    obj->worldBoundingSphere = rsMatrixMultiply(&objTransform->globalMat, obj->worldBoundingSphere);
+
+    const float4 unitVec = {0.57735f, 0.57735f, 0.57735f, 0.0f};
+    float4 scaledVec = rsMatrixMultiply(&objTransform->globalMat, unitVec);
+    scaledVec.w = 0.0f;
+    obj->worldBoundingSphere.w = obj->boundingSphere.w * length(scaledVec);
+}
+
+static bool frustumCulled(SgRenderable *obj, SgCamera *cam) {
+    if (!obj->bVolInitialized) {
+        float minX, minY, minZ, maxX, maxY, maxZ;
+        rsgMeshComputeBoundingBox(obj->mesh,
+                                  &minX, &minY, &minZ,
+                                  &maxX, &maxY, &maxZ);
+        //rsDebug("min", minX, minY, minZ);
+        //rsDebug("max", maxX, maxY, maxZ);
+        float4 sphere;
+        sphere.x = (maxX + minX) * 0.5f;
+        sphere.y = (maxY + minY) * 0.5f;
+        sphere.z = (maxZ + minZ) * 0.5f;
+        float3 radius;
+        radius.x = (maxX - sphere.x);
+        radius.y = (maxY - sphere.y);
+        radius.z = (maxZ - sphere.z);
+
+        sphere.w = length(radius);
+        obj->boundingSphere = sphere;
+        obj->bVolInitialized = 1;
+        //rsDebug("Sphere", sphere);
+    }
+
+    getTransformedSphere(obj);
+
+    return !rsIsSphereInFrustum(&obj->worldBoundingSphere,
+                                &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+                                &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+                                &cam->frustumPlanes[4], &cam->frustumPlanes[5]);
+}
+
+
+void root(rs_allocation *v_out, const void *usrData) {
+
+    SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
+    const SgCamera *camera = (const SgCamera*)usrData;
+
+    drawable->isVisible = 0;
+    // Not loaded yet
+    if (!rsIsObject(drawable->mesh) || drawable->cullType == CULL_ALWAYS) {
+        return;
+    }
+
+    // check to see if we are culling this object and if it's
+    // outside the frustum
+    if (drawable->cullType == CULL_FRUSTUM && frustumCulled(drawable, (SgCamera*)camera)) {
+#ifdef DEBUG_RENDERABLES
+        rsDebug("Culled", drawable);
+        printName(drawable->name);
+#endif // DEBUG_RENDERABLES
+        return;
+    }
+    drawable->isVisible = 1;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
new file mode 100644
index 0000000..b438a43
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
@@ -0,0 +1,61 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+// The sole purpose of this script is to have various structs exposed
+// so that java reflected classes are generated
+#include "scenegraph_objects.rsh"
+
+// Export our native constants to java so that we don't have parallel definitions
+const int ShaderParam_FLOAT4_DATA = SHADER_PARAM_FLOAT4_DATA;
+const int ShaderParam_TRANSFORM_DATA = SHADER_PARAM_TRANSFORM_DATA;
+const int ShaderParam_TRANSFORM_MODEL = SHADER_PARAM_TRANSFORM_MODEL;
+
+const int ShaderParam_FLOAT4_CAMERA_POS = SHADER_PARAM_FLOAT4_CAMERA_POS;
+const int ShaderParam_FLOAT4_CAMERA_DIR = SHADER_PARAM_FLOAT4_CAMERA_DIR;
+const int ShaderParam_TRANSFORM_VIEW = SHADER_PARAM_TRANSFORM_VIEW;
+const int ShaderParam_TRANSFORM_PROJ = SHADER_PARAM_TRANSFORM_PROJ;
+const int ShaderParam_TRANSFORM_VIEW_PROJ = SHADER_PARAM_TRANSFORM_VIEW_PROJ;
+const int ShaderParam_TRANSFORM_MODEL_VIEW = SHADER_PARAM_TRANSFORM_MODEL_VIEW;
+const int ShaderParam_TRANSFORM_MODEL_VIEW_PROJ = SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ;
+
+const int ShaderParam_FLOAT4_LIGHT_COLOR = SHADER_PARAM_FLOAT4_LIGHT_COLOR;
+const int ShaderParam_FLOAT4_LIGHT_POS = SHADER_PARAM_FLOAT4_LIGHT_POS;
+const int ShaderParam_FLOAT4_LIGHT_DIR = SHADER_PARAM_FLOAT4_LIGHT_DIR;
+
+const int ShaderParam_TEXTURE = SHADER_PARAM_TEXTURE;
+
+const int Transform_TRANSLATE = TRANSFORM_TRANSLATE;
+const int Transform_ROTATE = TRANSFORM_ROTATE;
+const int Transform_SCALE = TRANSFORM_SCALE;
+
+const int TextureType_TEXTURE_2D = TEXTURE_2D;
+const int TextureType_TEXTURE_CUBE = TEXTURE_CUBE;
+const int TextureType_TEXTURE_RENDER_TARGET = TEXTURE_RENDER_TARGET;
+
+SgTransform *exportPtr;
+SgTransformComponent *componentPtr;
+SgRenderState *sExport;
+SgRenderable *drExport;
+SgRenderPass *pExport;
+SgCamera *exportPtrCam;
+SgLight *exportPtrLight;
+SgShaderParam *spExport;
+SgShaderParamData *spDataExport;
+SgVertexShader *pvExport;
+SgFragmentShader *pfExport;
+SgTexture *texExport;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
new file mode 100644
index 0000000..7202285
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
@@ -0,0 +1,30 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+    SgFragmentShader *shader = (SgFragmentShader *)rsGetElementAt(*v_out, 0);
+    const SgCamera *camera = (const SgCamera*)usrData;
+    processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
+    processTextureParams(shader);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
new file mode 100644
index 0000000..e11979f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
@@ -0,0 +1,33 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+//#define DEBUG_LIGHT
+#include "scenegraph_objects.rsh"
+
+void root(const rs_allocation *v_in, rs_allocation *v_out) {
+
+    SgLight *light = (SgLight *)rsGetElementAt(*v_in, 0);
+    const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
+
+    float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
+    light->position = rsMatrixMultiply(&lTransform->globalMat, zero);
+
+#ifdef DEBUG_LIGHT
+    printLightInfo(light);
+#endif //DEBUG_LIGHT
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
new file mode 100644
index 0000000..0d524a6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
@@ -0,0 +1,36 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+
+    SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
+    // Visibility flag was set earlier in the cull stage
+    if (!drawable->isVisible) {
+        return;
+    }
+
+    const SgCamera *camera = (const SgCamera*)usrData;
+    processAllParams(drawable->pf_const, drawable->pf_constParams, camera);
+    processAllParams(drawable->pv_const, drawable->pv_constParams, camera);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
new file mode 100644
index 0000000..575794b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
@@ -0,0 +1,193 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+static void debugParam(SgShaderParam *p, SgShaderParamData *pData) {
+    rsDebug("____________ Param ____________", p);
+    printName(pData->paramName);
+    rsDebug("bufferOffset", p->bufferOffset);
+    rsDebug("type ", pData->type);
+    rsDebug("data timestamp ", pData->timestamp);
+    rsDebug("param timestamp", p->dataTimestamp);
+
+    const SgTransform *pTransform = NULL;
+    if (rsIsObject(pData->transform)) {
+        pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
+
+        rsDebug("transform", pTransform);
+        printName(pTransform->name);
+        rsDebug("timestamp", pTransform->timestamp);
+        rsDebug("param timestamp", p->transformTimestamp);
+    }
+
+    const SgLight *pLight = NULL;
+    if (rsIsObject(pData->light)) {
+        pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
+        printLightInfo(pLight);
+    }
+}
+
+
+static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
+#ifdef DEBUG_PARAMS
+    rsDebug("Writing value ", *input);
+    rsDebug("Writing vec size ", vecSize);
+#endif // DEBUG_PARAMS
+
+    switch (vecSize) {
+    case 1:
+        *ptr = input->x;
+        break;
+    case 2:
+        *((float2*)ptr) = (*input).xy;
+        break;
+    case 3:
+        *((float3*)ptr) = (*input).xyz;
+        break;
+    case 4:
+        *((float4*)ptr) = *input;
+        break;
+    }
+}
+
+static bool processParam(SgShaderParam *p, SgShaderParamData *pData,
+                         uint8_t *constantBuffer,
+                         const SgCamera *currentCam,
+                         SgFragmentShader *shader) {
+    bool isDataOnly = (pData->type > SHADER_PARAM_DATA_ONLY);
+    const SgTransform *pTransform = NULL;
+    if (rsIsObject(pData->transform)) {
+        pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
+    }
+
+    if (isDataOnly) {
+        // If we are a transform param and our transform is unchanged, nothing to do
+        if (pTransform) {
+            if (p->transformTimestamp == pTransform->timestamp) {
+                return false;
+            }
+            p->transformTimestamp = pTransform->timestamp;
+        } else {
+            if (p->dataTimestamp == pData->timestamp) {
+                return false;
+            }
+            p->dataTimestamp = pData->timestamp;
+        }
+    }
+
+    const SgLight *pLight = NULL;
+    if (rsIsObject(pData->light)) {
+        pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
+    }
+
+    uint8_t *dataPtr = NULL;
+    const SgTexture *tex = NULL;
+    if (pData->type == SHADER_PARAM_TEXTURE) {
+        tex = rsGetElementAt(pData->texture, 0);
+    } else {
+        dataPtr = constantBuffer + p->bufferOffset;
+    }
+
+    switch (pData->type) {
+    case SHADER_PARAM_TEXTURE:
+        rsgBindTexture(shader->program, p->bufferOffset, tex->texture);
+        break;
+    case SHADER_PARAM_FLOAT4_DATA:
+        writeFloatData((float*)dataPtr, &pData->float_value, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_CAMERA_POS:
+        writeFloatData((float*)dataPtr, &currentCam->position, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_CAMERA_DIR: break;
+    case SHADER_PARAM_FLOAT4_LIGHT_COLOR:
+        writeFloatData((float*)dataPtr, &pLight->color, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_LIGHT_POS:
+        writeFloatData((float*)dataPtr, &pLight->position, p->float_vecSize);
+        break;
+    case SHADER_PARAM_FLOAT4_LIGHT_DIR: break;
+
+    case SHADER_PARAM_TRANSFORM_DATA:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_VIEW:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+        break;
+    case SHADER_PARAM_TRANSFORM_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->proj);
+        break;
+    case SHADER_PARAM_TRANSFORM_VIEW_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL_VIEW:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+                             (rs_matrix4x4*)dataPtr,
+                             &pTransform->globalMat);
+        break;
+    case SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ:
+        rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+        rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+                             (rs_matrix4x4*)dataPtr,
+                             &pTransform->globalMat);
+        break;
+    }
+    return true;
+}
+
+static void processAllParams(rs_allocation shaderConst,
+                             rs_allocation allParams,
+                             const SgCamera *camera) {
+    if (rsIsObject(shaderConst)) {
+        uint8_t *constantBuffer = (uint8_t*)rsGetElementAt(shaderConst, 0);
+
+        int numParams = 0;
+        if (rsIsObject(allParams)) {
+            numParams = rsAllocationGetDimX(allParams);
+        }
+        bool updated = false;
+        for (int i = 0; i < numParams; i ++) {
+            SgShaderParam *current = (SgShaderParam*)rsGetElementAt(allParams, i);
+            SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
+#ifdef DEBUG_PARAMS
+            debugParam(current, currentData);
+#endif // DEBUG_PARAMS
+            updated = processParam(current, currentData, constantBuffer, camera, NULL) || updated;
+        }
+    }
+}
+
+static void processTextureParams(SgFragmentShader *shader) {
+    int numParams = 0;
+    if (rsIsObject(shader->shaderTextureParams)) {
+        numParams = rsAllocationGetDimX(shader->shaderTextureParams);
+    }
+    for (int i = 0; i < numParams; i ++) {
+        SgShaderParam *current = (SgShaderParam*)rsGetElementAt(shader->shaderTextureParams, i);
+        SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
+#ifdef DEBUG_PARAMS
+        debugParam(current, currentData);
+#endif // DEBUG_PARAMS
+        processParam(current, currentData, NULL, NULL, shader);
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
new file mode 100644
index 0000000..d8d48b3
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
@@ -0,0 +1,240 @@
+// Copyright (C) 2011-2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "rs_graphics.rsh"
+#include "scenegraph_objects.rsh"
+
+rs_script gTransformScript;
+rs_script gCameraScript;
+rs_script gLightScript;
+rs_script gObjectParamsScript;
+rs_script gFragmentParamsScript;
+rs_script gVertexParamsScript;
+rs_script gCullScript;
+
+SgTransform *gRootNode;
+rs_allocation gCameras;
+rs_allocation gLights;
+rs_allocation gFragmentShaders;
+rs_allocation gVertexShaders;
+rs_allocation gRenderableObjects;
+
+rs_allocation gRenderPasses;
+
+// Temporary shaders
+rs_program_store gPFSBackground;
+
+uint32_t *gFrontToBack;
+static uint32_t gFrontToBackCount = 0;
+uint32_t *gBackToFront;
+static uint32_t gBackToFrontCount = 0;
+
+static SgCamera *gActiveCamera = NULL;
+
+static rs_allocation nullAlloc;
+
+// #define DEBUG_RENDERABLES
+static void draw(SgRenderable *obj) {
+#ifdef DEBUG_RENDERABLES
+    const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
+    rsDebug("**** Drawing object with transform", obj);
+    printName(objTransform->name);
+    rsDebug("Model matrix: ", &objTransform->globalMat);
+    printName(obj->name);
+#endif //DEBUG_RENDERABLES
+
+    const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
+    const SgVertexShader *pv = (const SgVertexShader *)rsGetElementAt(renderState->pv, 0);
+    const SgFragmentShader *pf = (const SgFragmentShader *)rsGetElementAt(renderState->pf, 0);
+
+    if (pv->objectConstIndex != -1) {
+        rsgBindConstant(pv->program, pv->objectConstIndex, obj->pv_const);
+    }
+    if (pf->objectConstIndex != -1) {
+        rsgBindConstant(pf->program, pf->objectConstIndex, obj->pf_const);
+    }
+
+    if (rsIsObject(renderState->ps)) {
+        rsgBindProgramStore(renderState->ps);
+    } else {
+        rsgBindProgramStore(gPFSBackground);
+    }
+
+    if (rsIsObject(renderState->pr)) {
+        rsgBindProgramRaster(renderState->pr);
+    } else {
+        rs_program_raster pr;
+        rsgBindProgramRaster(pr);
+    }
+
+    rsgBindProgramVertex(pv->program);
+    rsgBindProgramFragment(pf->program);
+
+    for (uint32_t i = 0; i < obj->pf_num_textures; i ++) {
+        const SgTexture *tex = rsGetElementAt(obj->pf_textures[i], 0);
+        rsgBindTexture(pf->program, i, tex->texture);
+    }
+
+    rsgDrawMesh(obj->mesh, obj->meshIndex);
+}
+
+static void sortToBucket(SgRenderable *obj) {
+    const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
+    if (rsIsObject(renderState->ps)) {
+        bool isOpaque = false;
+        if (isOpaque) {
+            gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
+        } else {
+            gBackToFront[gBackToFrontCount++] = (uint32_t)obj;
+        }
+    } else {
+        gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
+    }
+}
+
+static void updateActiveCamera(rs_allocation cam) {
+    gActiveCamera = (SgCamera *)rsGetElementAt(cam, 0);
+}
+
+static void prepareCameras() {
+    // now compute all the camera matrices
+    if (rsIsObject(gCameras)) {
+        float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+        rsForEach(gCameraScript, gCameras, nullAlloc, &aspect, sizeof(aspect));
+    }
+}
+
+static void prepareLights() {
+    if (rsIsObject(gLights)) {
+        rsForEach(gLightScript, gLights, nullAlloc);
+    }
+}
+
+static void drawSorted() {
+    for (int i = 0; i < gFrontToBackCount; i ++) {
+        SgRenderable *current = (SgRenderable*)gFrontToBack[i];
+        draw(current);
+    }
+
+    for (int i = 0; i < gBackToFrontCount; i ++) {
+        SgRenderable *current = (SgRenderable*)gBackToFront[i];
+        draw(current);
+    }
+}
+
+static void drawAllObjects(rs_allocation allObj) {
+    if (!rsIsObject(allObj)) {
+        return;
+    }
+
+    rsForEach(gVertexParamsScript, nullAlloc, gVertexShaders,
+              gActiveCamera, sizeof(gActiveCamera));
+    rsForEach(gFragmentParamsScript, nullAlloc, gFragmentShaders,
+              gActiveCamera, sizeof(gActiveCamera));
+
+    // Run the params and cull script
+    rsForEach(gCullScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
+    rsForEach(gObjectParamsScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
+
+    int numRenderables = rsAllocationGetDimX(allObj);
+    for (int i = 0; i < numRenderables; i ++) {
+        rs_allocation *drawAlloc = (rs_allocation*)rsGetElementAt(allObj, i);
+        SgRenderable *current = (SgRenderable*)rsGetElementAt(*drawAlloc, 0);
+        if (current->isVisible) {
+            sortToBucket(current);
+        }
+    }
+    drawSorted();
+}
+
+int root(void) {
+#ifdef DEBUG_RENDERABLES
+    rsDebug("=============================================================================", 0);
+#endif // DEBUG_RENDERABLES
+
+    // first step is to update the transform hierachy
+    if (gRootNode && rsIsObject(gRootNode->children)) {
+        rsForEach(gTransformScript, gRootNode->children, nullAlloc, 0, 0);
+    }
+
+    prepareCameras();
+    prepareLights();
+
+    if (rsIsObject(gRenderPasses)) {
+        rsgClearDepth(1.0f);
+        int numPasses = rsAllocationGetDimX(gRenderPasses);
+        for (uint i = 0; i < numPasses; i ++) {
+            gFrontToBackCount = 0;
+            gBackToFrontCount = 0;
+            SgRenderPass *pass = (SgRenderPass*)rsGetElementAt(gRenderPasses, i);
+            if (rsIsObject(pass->color_target)) {
+                rsgBindColorTarget(pass->color_target, 0);
+            }
+            if (rsIsObject(pass->depth_target)) {
+                rsgBindDepthTarget(pass->depth_target);
+            }
+            if (!rsIsObject(pass->color_target) &&
+                !rsIsObject(pass->depth_target)) {
+                rsgClearAllRenderTargets();
+            }
+            updateActiveCamera(pass->camera);
+            if (pass->should_clear_color) {
+                rsgClearColor(pass->clear_color.x, pass->clear_color.y,
+                              pass->clear_color.z, pass->clear_color.w);
+            }
+            if (pass->should_clear_depth) {
+                rsgClearDepth(pass->clear_depth);
+            }
+            drawAllObjects(pass->objects);
+        }
+    } else {
+        gFrontToBackCount = 0;
+        gBackToFrontCount = 0;
+        rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+        rsgClearDepth(1.0f);
+
+        if (rsIsObject(gCameras)) {
+            rs_allocation *camAlloc = (rs_allocation*)rsGetElementAt(gCameras, 0);
+            updateActiveCamera(*camAlloc);
+        }
+        drawAllObjects(gRenderableObjects);
+    }
+    return 10;
+}
+
+// Search through sorted and culled objects
+void pick(int screenX, int screenY) {
+    float3 pnt, vec;
+    getCameraRay(gActiveCamera, screenX, screenY, &pnt, &vec);
+
+    for (int i = 0; i < gFrontToBackCount; i ++) {
+        SgRenderable *current = (SgRenderable*)gFrontToBack[i];
+        bool isPicked = intersect(current, pnt, vec);
+        if (isPicked) {
+            current->cullType = CULL_ALWAYS;
+        }
+    }
+
+    for (int i = 0; i < gBackToFrontCount; i ++) {
+        SgRenderable *current = (SgRenderable*)gBackToFront[i];
+        bool isPicked = intersect(current, pnt, vec);
+        if (isPicked) {
+            current->cullType = CULL_ALWAYS;
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
new file mode 100644
index 0000000..bdca3ab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
@@ -0,0 +1,323 @@
+// Copyright (C) 2011-2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#ifndef _TRANSFORM_DEF_
+#define _TRANSFORM_DEF_
+
+#include "rs_graphics.rsh"
+
+#define TRANSFORM_NONE      0
+#define TRANSFORM_TRANSLATE 1
+#define TRANSFORM_ROTATE    2
+#define TRANSFORM_SCALE     3
+
+#define CULL_FRUSTUM 0
+#define CULL_ALWAYS  2
+
+#define LIGHT_POINT       0
+#define LIGHT_DIRECTIONAL 1
+
+// Shader params that involve only data
+#define SHADER_PARAM_DATA_ONLY                 10000
+#define SHADER_PARAM_FLOAT4_DATA               10001
+#define SHADER_PARAM_TRANSFORM_DATA            10002
+#define SHADER_PARAM_TRANSFORM_MODEL           10003
+
+// Shader params that involve camera
+#define SHADER_PARAM_CAMERA                    1000
+#define SHADER_PARAM_FLOAT4_CAMERA_POS         1001
+#define SHADER_PARAM_FLOAT4_CAMERA_DIR         1002
+#define SHADER_PARAM_TRANSFORM_VIEW            1003
+#define SHADER_PARAM_TRANSFORM_PROJ            1004
+#define SHADER_PARAM_TRANSFORM_VIEW_PROJ       1005
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW      1006
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ 1007
+
+// Shader Params that only involve lights
+#define SHADER_PARAM_LIGHT                     100
+#define SHADER_PARAM_FLOAT4_LIGHT_COLOR        103
+#define SHADER_PARAM_FLOAT4_LIGHT_POS          104
+#define SHADER_PARAM_FLOAT4_LIGHT_DIR          105
+
+#define SHADER_PARAM_TEXTURE                   10
+
+#define TEXTURE_NONE          0
+#define TEXTURE_2D            1
+#define TEXTURE_CUBE          2
+#define TEXTURE_RENDER_TARGET 3
+
+typedef struct TransformComponent_s {
+    float4 value;
+    int type;
+    rs_allocation name;
+} SgTransformComponent;
+
+typedef struct __attribute__((packed, aligned(4))) SgTransform {
+    rs_matrix4x4 globalMat;
+    rs_matrix4x4 localMat;
+
+    rs_allocation components;
+    int isDirty;
+
+    rs_allocation children;
+    rs_allocation name;
+
+    // Used to check whether transform params need to be updated
+    uint32_t timestamp;
+} SgTransform;
+
+typedef struct VertexShader_s {
+    rs_program_vertex program;
+    // Buffer with vertex constant data
+    rs_allocation shaderConst;
+    // ShaderParam's that populate data
+    rs_allocation shaderConstParams;
+    // location of the per object constants on the buffer
+    int objectConstIndex;
+} SgVertexShader;
+
+typedef struct FragmentShader_s {
+    rs_program_fragment program;
+    // Buffer with vertex constant data
+    rs_allocation shaderConst;
+    // ShaderParam's that populate data
+    rs_allocation shaderConstParams;
+    // ShaderParam's that set textures
+    rs_allocation shaderTextureParams;
+    // location of the per object constants on the buffer
+    int objectConstIndex;
+} SgFragmentShader;
+
+typedef struct RenderState_s {
+    rs_allocation pv; // VertexShader struct
+    rs_allocation pf; // FragmentShader struct
+    rs_program_store ps;
+    rs_program_raster pr;
+} SgRenderState;
+
+typedef struct Renderable_s {
+    rs_allocation render_state;
+    // Buffer with vertex constant data
+    rs_allocation pv_const;
+    // ShaderParam's that populate data
+    rs_allocation pv_constParams;
+    // Buffer with fragment constant data
+    rs_allocation pf_const;
+    // ShaderParam's that populate data
+    rs_allocation pf_constParams;
+    rs_allocation pf_textures[8];
+    int pf_num_textures;
+    rs_mesh mesh;
+    int meshIndex;
+    rs_allocation transformMatrix;
+    rs_allocation name;
+    float4 boundingSphere;
+    float4 worldBoundingSphere;
+    int bVolInitialized;
+    int cullType; // specifies whether to frustum cull
+    int isVisible;
+} SgRenderable;
+
+typedef struct RenderPass_s {
+    rs_allocation color_target;
+    rs_allocation depth_target;
+    rs_allocation camera;
+    rs_allocation objects;
+
+    float4 clear_color;
+    float clear_depth;
+    bool should_clear_color;
+    bool should_clear_depth;
+} SgRenderPass;
+
+typedef struct Camera_s {
+    rs_matrix4x4 proj;
+    rs_matrix4x4 view;
+    rs_matrix4x4 viewProj;
+    float4 position;
+    float near;
+    float far;
+    float horizontalFOV;
+    float aspect;
+    rs_allocation name;
+    rs_allocation transformMatrix;
+    float4 frustumPlanes[6];
+
+    int isDirty;
+    // Timestamp of the camera itself to signal params if anything changes
+    uint32_t timestamp;
+    // Timestamp of our transform
+    uint32_t transformTimestamp;
+} SgCamera;
+
+typedef struct Light_s {
+    float4 position;
+    float4 color;
+    float intensity;
+    int type;
+    rs_allocation name;
+    rs_allocation transformMatrix;
+} SgLight;
+
+// This represents the shader parameter data needed to set a float or transform data
+typedef struct ShaderParamData_s {
+    int type;
+    float4 float_value;
+    uint32_t timestamp;
+    rs_allocation paramName;
+    rs_allocation camera;
+    rs_allocation light;
+    rs_allocation transform;
+    rs_allocation texture;
+} SgShaderParamData;
+
+// This represents a shader parameter that knows how to update itself for a given
+// renderable or shader and contains a timestamp for the last time this buffer was updated
+typedef struct ShaderParam_s {
+    // Used to check whether transform params need to be updated
+    uint32_t transformTimestamp;
+    // Used to check whether data params need to be updated
+    // These are used when somebody set the matrix of float value directly in java
+    uint32_t dataTimestamp;
+    // Specifies where in the constant buffer data gets written to
+    int bufferOffset;
+    // An instance of SgShaderParamData that could be shared by multiple objects
+    rs_allocation data;
+    // How many components of the vector we need to write
+    int float_vecSize;
+} SgShaderParam;
+
+// This represents a texture object
+typedef struct Texture_s {
+    uint32_t type;
+    rs_allocation texture;
+} SgTexture;
+
+static void printName(rs_allocation name) {
+    if (!rsIsObject(name)) {
+        rsDebug("no name", 0);
+        return;
+    }
+
+    rsDebug((const char*)rsGetElementAt(name, 0), 0);
+}
+
+static void printCameraInfo(const SgCamera *cam) {
+    rsDebug("***** Camera information. ptr:", cam);
+    printName(cam->name);
+    const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
+    rsDebug("Transform name:", camTransform);
+    printName(camTransform->name);
+
+    rsDebug("Aspect: ", cam->aspect);
+    rsDebug("Near: ", cam->near);
+    rsDebug("Far: ", cam->far);
+    rsDebug("Fov: ", cam->horizontalFOV);
+    rsDebug("Position: ", cam->position);
+    rsDebug("Proj: ", &cam->proj);
+    rsDebug("View: ", &cam->view);
+}
+
+static void printLightInfo(const SgLight *light) {
+    rsDebug("***** Light information. ptr:", light);
+    printName(light->name);
+    const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
+    rsDebug("Transform name:", lTransform);
+    printName(lTransform->name);
+
+    rsDebug("Position: ", light->position);
+    rsDebug("Color : ", light->color);
+    rsDebug("Intensity: ", light->intensity);
+    rsDebug("Type: ", light->type);
+}
+
+static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) {
+    rsDebug("=================================", screenX);
+    rsDebug("Point X", screenX);
+    rsDebug("Point Y", screenY);
+
+    rs_matrix4x4 mvpInv;
+    rsMatrixLoad(&mvpInv, &cam->viewProj);
+    rsMatrixInverse(&mvpInv);
+
+    float width = (float)rsgGetWidth();
+    float height = (float)rsgGetHeight();
+
+    float4 pos = {(float)screenX, height - (float)screenY, 0.0f, 1.0f};
+
+    pos.x /= width;
+    pos.y /= height;
+
+    rsDebug("Pre Norm X", pos.x);
+    rsDebug("Pre Norm Y", pos.y);
+
+    pos.xy = pos.xy * 2.0f - 1.0f;
+
+    rsDebug("Norm X", pos.x);
+    rsDebug("Norm Y", pos.y);
+
+    pos = rsMatrixMultiply(&mvpInv, pos);
+    float oneOverW = 1.0f / pos.w;
+    pos.xyz *= oneOverW;
+
+    rsDebug("World X", pos.x);
+    rsDebug("World Y", pos.y);
+    rsDebug("World Z", pos.z);
+
+    rsDebug("Cam X", cam->position.x);
+    rsDebug("Cam Y", cam->position.y);
+    rsDebug("Cam Z", cam->position.z);
+
+    *vec = normalize(pos.xyz - cam->position.xyz);
+    rsDebug("Vec X", vec->x);
+    rsDebug("Vec Y", vec->y);
+    rsDebug("Vec Z", vec->z);
+    *pnt = cam->position.xyz;
+}
+
+static bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) {
+    // Solving for t^2 + Bt + C = 0
+    float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz;
+    float B = dot(originMinusCenter, vec) * 2.0f;
+    float C = dot(originMinusCenter, originMinusCenter) -
+              obj->worldBoundingSphere.w * obj->worldBoundingSphere.w;
+
+    float discriminant = B * B - 4.0f * C;
+    if (discriminant < 0.0f) {
+        return false;
+    }
+    discriminant = sqrt(discriminant);
+
+    float t0 = (-B - discriminant) * 0.5f;
+    float t1 = (-B + discriminant) * 0.5f;
+
+    if (t0 > t1) {
+        float temp = t0;
+        t0 = t1;
+        t1 = temp;
+    }
+
+    // The sphere is behind us
+    if (t1 < 0.0f) {
+        return false;
+    }
+    return true;
+}
+
+
+#endif // _TRANSFORM_DEF_
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
new file mode 100644
index 0000000..941b5a8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
@@ -0,0 +1,127 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.modelviewer)
+
+#include "scenegraph_objects.rsh"
+
+rs_script gTransformScript;
+
+typedef struct {
+    int changed;
+    rs_matrix4x4 *mat;
+} ParentData;
+
+//#define DEBUG_TRANSFORMS
+static void debugTransform(SgTransform *data, const ParentData *parent) {
+    rsDebug("****** <Transform> ******", (int)data);
+    printName(data->name);
+    rsDebug("isDirty", data->isDirty);
+    rsDebug("parent", (int)parent);
+    rsDebug("child ", rsIsObject(data->children));
+
+    // Refresh matrices if dirty
+    if (data->isDirty && rsIsObject(data->components)) {
+        uint32_t numComponenets = rsAllocationGetDimX(data->components);
+        for (int i = 0; i < numComponenets; i ++) {
+            const SgTransformComponent *comp = NULL;
+            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
+
+            if (rsIsObject(comp->name)) {
+                rsDebug((const char*)rsGetElementAt(comp->name, 0), comp->value);
+                rsDebug("Type", comp->type);
+            } else {
+                rsDebug("no name", comp->value);
+                rsDebug("Type", comp->type);
+            }
+        }
+    }
+
+    rsDebug("timestamp", data->timestamp);
+    rsDebug("****** </Transform> ******", (int)data);
+}
+
+static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) {
+    rs_matrix4x4 temp;
+
+    switch (type) {
+    case TRANSFORM_TRANSLATE:
+        rsMatrixLoadTranslate(&temp, data.x, data.y, data.z);
+        break;
+    case TRANSFORM_ROTATE:
+        rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z);
+        break;
+    case TRANSFORM_SCALE:
+        rsMatrixLoadScale(&temp, data.x, data.y, data.z);
+        break;
+    }
+    rsMatrixMultiply(mat, &temp);
+}
+
+void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) {
+
+    SgTransform *data = (SgTransform *)rsGetElementAt(*v_in, 0);
+    const ParentData *parent = (const ParentData *)usrData;
+
+#ifdef DEBUG_TRANSFORMS
+    debugTransform(data, parent);
+#endif //DEBUG_TRANSFORMS
+
+    rs_matrix4x4 *localMat = &data->localMat;
+    rs_matrix4x4 *globalMat = &data->globalMat;
+
+    // Refresh matrices if dirty
+    if (data->isDirty && rsIsObject(data->components)) {
+        bool resetLocal = false;
+        uint32_t numComponenets = rsAllocationGetDimX(data->components);
+        for (int i = 0; i < numComponenets; i ++) {
+            if (!resetLocal) {
+                // Reset our local matrix only for component transforms
+                rsMatrixLoadIdentity(localMat);
+                resetLocal = true;
+            }
+            const SgTransformComponent *comp = NULL;
+            comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
+            appendTransformation(comp->type, comp->value, localMat);
+        }
+    }
+
+    if (parent) {
+        data->isDirty = (parent->changed || data->isDirty) ? 1 : 0;
+        if (data->isDirty) {
+            rsMatrixLoad(globalMat, parent->mat);
+            rsMatrixMultiply(globalMat, localMat);
+        }
+    } else if (data->isDirty) {
+        rsMatrixLoad(globalMat, localMat);
+    }
+
+    ParentData toChild;
+    toChild.changed = 0;
+    toChild.mat = globalMat;
+
+    if (data->isDirty) {
+        toChild.changed = 1;
+        data->timestamp ++;
+    }
+
+    if (rsIsObject(data->children)) {
+        rs_allocation nullAlloc;
+        rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild));
+    }
+
+    data->isDirty = 0;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
new file mode 100644
index 0000000..88955a8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
@@ -0,0 +1,29 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+    SgVertexShader *shader = (SgVertexShader *)rsGetElementAt(*v_out, 0);
+    const SgCamera *camera = (const SgCamera*)usrData;
+    processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
new file mode 100644
index 0000000..420e133
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+/**
+ * A list view where the last item the user clicked is placed in
+ * the "activated" state, causing its background to highlight.
+ */
+public class FileSelector extends ListActivity {
+
+    File[] mCurrentSubList;
+    File mCurrentFile;
+
+    class DAEFilter implements FileFilter {
+        public boolean accept(File file) {
+            if (file.isDirectory()) {
+                return true;
+            }
+            return file.getName().endsWith(".dae");
+        }
+    }
+
+    private void populateList(File file) {
+
+        mCurrentFile = file;
+        setTitle(mCurrentFile.getAbsolutePath() + "/*.dae");
+        List<String> names = new ArrayList<String>();
+        names.add("..");
+
+        mCurrentSubList = mCurrentFile.listFiles(new DAEFilter());
+
+        if (mCurrentSubList != null) {
+            for (int i = 0; i < mCurrentSubList.length; i ++) {
+                String fileName = mCurrentSubList[i].getName();
+                if (mCurrentSubList[i].isDirectory()) {
+                    fileName = "/" + fileName;
+                }
+                names.add(fileName);
+            }
+        }
+
+        // Use the built-in layout for showing a list item with a single
+        // line of text whose background is changes when activated.
+        setListAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_activated_1, names));
+        getListView().setTextFilterEnabled(true);
+
+        // Tell the list view to show one checked/activated item at a time.
+        getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        populateList(new File("/sdcard/"));
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        if (position == 0) {
+            File parent = mCurrentFile.getParentFile();
+            if (parent == null) {
+                return;
+            }
+            populateList(parent);
+            return;
+        }
+
+        // the first thing in list is parent directory
+        File selectedFile = mCurrentSubList[position - 1];
+        if (selectedFile.isDirectory()) {
+            populateList(selectedFile);
+            return;
+        }
+
+        Intent resultIntent = new Intent();
+        resultIntent.setData(Uri.fromFile(selectedFile));
+        setResult(RESULT_OK, resultIntent);
+        finish();
+    }
+
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
new file mode 100644
index 0000000..28f916c
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
@@ -0,0 +1,192 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+package com.android.testapp;

+

+import java.util.ArrayList;

+

+import com.android.scenegraph.*;

+

+import android.content.res.Resources;

+import android.graphics.Bitmap;

+import android.graphics.BitmapFactory;

+import android.os.AsyncTask;

+import android.renderscript.*;

+import android.renderscript.Allocation.MipmapControl;

+import android.renderscript.Element.Builder;

+import android.renderscript.Font.Style;

+import android.renderscript.Program.TextureType;

+import android.renderscript.ProgramStore.DepthFunc;

+import android.util.Log;

+

+class FullscreenBlur {

+

+    static TextureRenderTarget sRenderTargetBlur0Color;

+    static TextureRenderTarget sRenderTargetBlur0Depth;

+    static TextureRenderTarget sRenderTargetBlur1Color;

+    static TextureRenderTarget sRenderTargetBlur1Depth;

+    static TextureRenderTarget sRenderTargetBlur2Color;

+    static TextureRenderTarget sRenderTargetBlur2Depth;

+

+    static FragmentShader mPF_BlurH;

+    static FragmentShader mPF_BlurV;

+    static FragmentShader mPF_SelectColor;

+    static FragmentShader mPF_Texture;

+    static VertexShader mPV_Paint;

+    static VertexShader mPV_Blur;

+

+    static int targetWidth;

+    static int targetHeight;

+

+    // This is only used when full screen blur is enabled

+    // Basically, it's the offscreen render targets

+    static void createRenderTargets(RenderScriptGL rs, int w, int h) {

+        targetWidth = w/8;

+        targetHeight = h/8;

+        Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));

+        Type renderType = b.setX(targetWidth).setY(targetHeight).create();

+        int usage = Allocation.USAGE_GRAPHICS_TEXTURE | Allocation.USAGE_GRAPHICS_RENDER_TARGET;

+        sRenderTargetBlur0Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+        sRenderTargetBlur1Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+        sRenderTargetBlur2Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+

+        b = new Type.Builder(rs, Element.createPixel(rs, Element.DataType.UNSIGNED_16,

+                                                     Element.DataKind.PIXEL_DEPTH));

+        renderType = b.setX(targetWidth).setY(targetHeight).create();

+        usage = Allocation.USAGE_GRAPHICS_RENDER_TARGET;

+        sRenderTargetBlur0Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+        sRenderTargetBlur1Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+        sRenderTargetBlur2Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));

+    }

+

+    static void addOffsets(Renderable quad, float advance) {

+        quad.appendSourceParams(new Float4Param("blurOffset0", - advance * 2.5f));

+        quad.appendSourceParams(new Float4Param("blurOffset1", - advance * 0.5f));

+        quad.appendSourceParams(new Float4Param("blurOffset2", advance * 1.5f));

+        quad.appendSourceParams(new Float4Param("blurOffset3", advance * 3.5f));

+    }

+

+    static RenderPass addPass(Scene scene, Camera cam, TextureRenderTarget color, TextureRenderTarget depth) {

+        RenderPass pass = new RenderPass();

+        pass.setColorTarget(color);

+        pass.setDepthTarget(depth);

+        pass.setShouldClearColor(false);

+        pass.setShouldClearDepth(false);

+        pass.setCamera(cam);

+        scene.appendRenderPass(pass);

+        return pass;

+    }

+

+    static void addBlurPasses(Scene scene, RenderScriptGL rs, Camera cam) {

+        SceneManager sceneManager = SceneManager.getInstance();

+        ArrayList<RenderableBase> allDraw = scene.getRenderables();

+        int numDraw = allDraw.size();

+

+        ProgramRaster cullNone = ProgramRaster.CULL_NONE(rs);

+        ProgramStore blendAdd = SceneManager.BLEND_ADD_DEPTH_NONE(rs);

+        ProgramStore blendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(rs);

+

+        RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture, blendAdd, cullNone);

+        RenderState selectCol = new RenderState(mPV_Blur, mPF_SelectColor, blendNone, cullNone);

+        RenderState hBlur = new RenderState(mPV_Blur, mPF_BlurH, blendNone, cullNone);

+        RenderState vBlur = new RenderState(mPV_Blur, mPF_BlurV, blendNone, cullNone);

+

+        // Renders the scene off screen

+        RenderPass blurSourcePass = addPass(scene, cam,

+                                            sRenderTargetBlur0Color,

+                                            sRenderTargetBlur0Depth);

+        blurSourcePass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));

+        blurSourcePass.setShouldClearColor(true);

+        blurSourcePass.setClearDepth(1.0f);

+        blurSourcePass.setShouldClearDepth(true);

+        for (int i = 0; i < numDraw; i ++) {

+            blurSourcePass.appendRenderable((Renderable)allDraw.get(i));

+        }

+

+        // Pass for selecting bright colors

+        RenderPass selectColorPass = addPass(scene, cam,

+                                             sRenderTargetBlur2Color,

+                                             sRenderTargetBlur2Depth);

+        Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadS", selectCol);

+        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur0Color));

+        selectColorPass.appendRenderable(quad);

+

+        // Horizontal blur

+        RenderPass horizontalBlurPass = addPass(scene, cam,

+                                                sRenderTargetBlur1Color,

+                                                sRenderTargetBlur1Depth);

+        quad = sceneManager.getRenderableQuad("ScreenAlignedQuadH", hBlur);

+        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));

+        addOffsets(quad, 1.0f / (float)targetWidth);

+        horizontalBlurPass.appendRenderable(quad);

+

+        // Vertical Blur

+        RenderPass verticalBlurPass = addPass(scene, cam,

+                                              sRenderTargetBlur2Color,

+                                              sRenderTargetBlur2Depth);

+        quad = sceneManager.getRenderableQuad("ScreenAlignedQuadV", vBlur);

+        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur1Color));

+        addOffsets(quad, 1.0f / (float)targetHeight);

+        verticalBlurPass.appendRenderable(quad);

+    }

+

+    // Additively renders the blurred colors on top of the scene

+    static void addCompositePass(Scene scene, RenderScriptGL rs, Camera cam) {

+        SceneManager sceneManager = SceneManager.getInstance();

+        RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture,

+                                              SceneManager.BLEND_ADD_DEPTH_NONE(rs),

+                                              ProgramRaster.CULL_NONE(rs));

+

+        RenderPass compositePass = addPass(scene, cam, null, null);

+        Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadComposite", drawTex);

+        quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));

+        compositePass.appendRenderable(quad);

+    }

+

+    static private FragmentShader getShader(Resources res, RenderScriptGL rs,

+                                            int resID, Type constants) {

+        FragmentShader.Builder fb = new FragmentShader.Builder(rs);

+        fb.setShader(res, resID);

+        fb.addTexture(TextureType.TEXTURE_2D, "color");

+        if (constants != null) {

+            fb.setObjectConst(constants);

+        }

+        FragmentShader prog = fb.create();

+        prog.getProgram().bindSampler(Sampler.CLAMP_LINEAR(rs), 0);

+        return prog;

+    }

+

+    static void initShaders(Resources res, RenderScriptGL rs) {

+        ScriptField_BlurOffsets blurConst = new ScriptField_BlurOffsets(rs, 1);

+        VertexShader.Builder vb = new VertexShader.Builder(rs);

+        vb.addInput(ScriptField_VertexShaderInputs.createElement(rs));

+        vb.setShader(res, R.raw.blur_vertex);

+        mPV_Blur = vb.create();

+

+        mPF_Texture = getShader(res, rs, R.raw.texture, null);

+        mPF_Texture.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(rs), 0);

+        mPF_BlurH = getShader(res, rs, R.raw.blur_h, blurConst.getAllocation().getType());

+        mPF_BlurV = getShader(res, rs, R.raw.blur_v, blurConst.getAllocation().getType());

+        mPF_SelectColor = getShader(res, rs, R.raw.select_color, null);

+    }

+

+}

+

+

+

+

+

diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
new file mode 100644
index 0000000..385a7ab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+import android.view.MenuInflater;
+import android.view.Window;
+import android.net.Uri;
+
+import java.lang.Runtime;
+
+public class TestApp extends Activity {
+
+    private TestAppView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // Create our Preview view and set it as the content of our
+        // Activity
+        mView = new TestAppView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onResume();
+        mView.resume();
+    }
+
+    @Override
+    protected void onPause() {
+        // Ideally a game should implement onResume() and onPause()
+        // to take appropriate action when the activity looses focus
+        super.onPause();
+        mView.pause();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.loader_menu, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        // Handle item selection
+        switch (item.getItemId()) {
+        case R.id.load_model:
+            loadModel();
+            return true;
+        case R.id.use_blur:
+            mView.mRender.toggleBlur();
+            return true;
+        default:
+            return super.onOptionsItemSelected(item);
+        }
+    }
+
+    private static final int FIND_DAE_MODEL = 10;
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode == RESULT_OK) {
+            if (requestCode == FIND_DAE_MODEL) {
+                Uri selectedImageUri = data.getData();
+                Log.e("Selected Path: ", selectedImageUri.getPath());
+                mView.mRender.loadModel(selectedImageUri.getPath());
+            }
+        }
+    }
+
+    public void loadModel() {
+        Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_PICK);
+        intent.setClassName("com.android.testapp",
+                            "com.android.testapp.FileSelector");
+        startActivityForResult(intent, FIND_DAE_MODEL);
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
new file mode 100644
index 0000000..5bd8f0b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+// This is where the scenegraph and the rendered objects are initialized and used
+public class TestAppLoadingScreen {
+
+    private static String TAG = "TestAppLoadingScreen";
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+    private ScriptC_test_app mScript;
+
+    public TestAppLoadingScreen(RenderScriptGL rs, Resources res) {
+        mRS = rs;
+        mRes = res;
+        // Shows the loading screen with some text
+        renderLoading();
+        // Adds a little 3D bugdroid model to the laoding screen asynchronously.
+        new LoadingScreenLoaderTask().execute();
+    }
+
+    public void showLoadingScreen(boolean show) {
+        if (show) {
+            mRS.bindRootScript(mScript);
+        } else {
+            mRS.bindRootScript(SceneManager.getInstance().getRenderLoop());
+        }
+    }
+
+    // The loading screen has some elements that shouldn't be loaded on the UI thread
+    private class LoadingScreenLoaderTask extends AsyncTask<String, Void, Boolean> {
+        Allocation robotTex;
+        Mesh robotMesh;
+        protected Boolean doInBackground(String... names) {
+            long start = System.currentTimeMillis();
+            robotTex = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
+                                                           MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+                                                           Allocation.USAGE_GRAPHICS_TEXTURE);
+
+            FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
+            FileA3D.IndexEntry entry = model.getIndexEntry(0);
+            if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+                robotMesh = entry.getMesh();
+            }
+
+            mScript.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
+
+            ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
+            b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+                         ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+            ProgramFragment pfDefault = b.create();
+            pfDefault.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
+            mScript.set_gPFBackground(pfDefault);
+
+            ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
+            ProgramVertexFixedFunction pvDefault = pvb.create();
+            ProgramVertexFixedFunction.Constants va = new ProgramVertexFixedFunction.Constants(mRS);
+            ((ProgramVertexFixedFunction)pvDefault).bindConstants(va);
+            mScript.set_gPVBackground(pvDefault);
+
+            long end = System.currentTimeMillis();
+            Log.v("TIMER", "Loading load time: " + (end - start));
+            return new Boolean(true);
+        }
+
+        protected void onPostExecute(Boolean result) {
+            mScript.set_gRobotTex(robotTex);
+            mScript.set_gRobotMesh(robotMesh);
+        }
+    }
+
+    // Creates a simple script to show a loding screen until everything is initialized
+    // Could also be used to do some custom renderscript work before handing things over
+    // to the scenegraph
+    void renderLoading() {
+        mScript = new ScriptC_test_app(mRS, mRes, R.raw.test_app);
+        mRS.bindRootScript(mScript);
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
new file mode 100644
index 0000000..7bf7812
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011-2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import com.android.scenegraph.*;
+import com.android.scenegraph.SceneManager.SceneLoadedCallback;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Program.TextureType;
+import android.util.Log;
+
+// This is where the scenegraph and the rendered objects are initialized and used
+public class TestAppRS {
+
+    private static String modelName = "orientation_test.dae";
+    private static String TAG = "TestAppRS";
+    private static String mFilePath = "";
+
+    int mWidth;
+    int mHeight;
+
+    boolean mUseBlur;
+
+    TestAppLoadingScreen mLoadingScreen;
+
+    // Used to asynchronously load scene elements like meshes and transform hierarchies
+    SceneLoadedCallback mLoadedCallback = new SceneLoadedCallback() {
+        public void run() {
+            prepareToRender(mLoadedScene);
+        }
+    };
+
+    // Top level class that initializes all the elements needed to use the scene graph
+    SceneManager mSceneManager;
+
+    // Used to move the camera around in the 3D world
+    TouchHandler mTouchHandler;
+
+    private Resources mRes;
+    private RenderScriptGL mRS;
+
+    // Shaders
+    private FragmentShader mPaintF;
+    private FragmentShader mLightsF;
+    private FragmentShader mAluminumF;
+    private FragmentShader mPlasticF;
+    private FragmentShader mDiffuseF;
+    private FragmentShader mTextureF;
+    private VertexShader mGenericV;
+
+    Scene mActiveScene;
+
+    // This is a part of the test app, it's used to tests multiple render passes and is toggled
+    // on and off in the menu, off by default
+    void toggleBlur() {
+        mUseBlur = !mUseBlur;
+
+        mActiveScene.clearRenderPasses();
+        initRenderPasses();
+        mActiveScene.initRenderPassRS(mRS, mSceneManager);
+
+        // This is just a hardcoded object in the scene that gets turned on and off for the demo
+        // to make things look a bit better. This could be deleted in the cleanup
+        Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
+        if (plane != null) {
+            plane.setVisible(!mUseBlur);
+        }
+    }
+
+    public void init(RenderScriptGL rs, Resources res, int width, int height) {
+        mUseBlur = false;
+        mRS = rs;
+        mRes = res;
+        mWidth = width;
+        mHeight = height;
+
+        mTouchHandler = new TouchHandler();
+
+        mSceneManager = SceneManager.getInstance();
+        // Initializes all the RS specific scenegraph elements
+        mSceneManager.initRS(mRS, mRes, mWidth, mHeight);
+
+        mLoadingScreen = new TestAppLoadingScreen(mRS, mRes);
+
+        // Initi renderscript stuff specific to the app. This will need to be abstracted out later.
+        FullscreenBlur.createRenderTargets(mRS, mWidth, mHeight);
+        initPaintShaders();
+
+        // Load a scene to render
+        mSceneManager.loadModel(mFilePath + modelName, mLoadedCallback);
+    }
+
+    // When a new model file is selected from the UI, this function gets called to init everything
+    void loadModel(String path) {
+        mLoadingScreen.showLoadingScreen(true);
+        mActiveScene.destroyRS();
+        mSceneManager.loadModel(path, mLoadedCallback);
+    }
+
+    public void onActionDown(float x, float y) {
+        mTouchHandler.onActionDown(x, y);
+    }
+
+    public void onActionScale(float scale) {
+        mTouchHandler.onActionScale(scale);
+    }
+
+    public void onActionMove(float x, float y) {
+        mTouchHandler.onActionMove(x, y);
+    }
+
+    FragmentShader createFromResource(int id, boolean addCubemap, Type constType) {
+        FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
+        fb.setShaderConst(constType);
+        fb.setShader(mRes, id);
+        fb.addTexture(TextureType.TEXTURE_2D, "diffuse");
+        if (addCubemap) {
+            fb.addShaderTexture(TextureType.TEXTURE_CUBE, "reflection");
+        }
+        FragmentShader pf = fb.create();
+        pf.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0);
+        if (addCubemap) {
+            pf.getProgram().bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(mRS), 1);
+        }
+        return pf;
+    }
+
+    private void initPaintShaders() {
+        ScriptField_ModelParams objConst = new ScriptField_ModelParams(mRS, 1);
+        ScriptField_ViewProjParams shaderConst = new ScriptField_ViewProjParams(mRS, 1);
+
+        VertexShader.Builder vb = new VertexShader.Builder(mRS);
+        vb.addInput(ScriptField_VertexShaderInputs.createElement(mRS));
+        vb.setShader(mRes, R.raw.shader2v);
+        vb.setObjectConst(objConst.getAllocation().getType());
+        vb.setShaderConst(shaderConst.getAllocation().getType());
+        mGenericV = vb.create();
+
+        ScriptField_CameraParams fsConst = new ScriptField_CameraParams(mRS, 1);
+        ScriptField_LightParams fsConst2 = new ScriptField_LightParams(mRS, 1);
+
+        mPaintF = createFromResource(R.raw.paintf, true, fsConst.getAllocation().getType());
+        // Assign a reflection map
+        TextureCube envCube = new TextureCube("sdcard/scenegraph/", "cube_env.png");
+        mPaintF.appendSourceParams(new TextureParam("reflection", envCube));
+
+        mAluminumF = createFromResource(R.raw.metal, true, fsConst.getAllocation().getType());
+        TextureCube diffCube = new TextureCube("sdcard/scenegraph/", "cube_spec.png");
+        mAluminumF.appendSourceParams(new TextureParam("reflection", diffCube));
+
+        mPlasticF = createFromResource(R.raw.plastic, false, fsConst.getAllocation().getType());
+        mDiffuseF = createFromResource(R.raw.diffuse, false, fsConst.getAllocation().getType());
+        mTextureF = createFromResource(R.raw.texture, false, fsConst.getAllocation().getType());
+
+        FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
+        fb.setObjectConst(fsConst2.getAllocation().getType());
+        fb.setShader(mRes, R.raw.plastic_lights);
+        mLightsF = fb.create();
+
+        FullscreenBlur.initShaders(mRes, mRS);
+    }
+
+    void initRenderPasses() {
+        ArrayList<RenderableBase> allDraw = mActiveScene.getRenderables();
+        int numDraw = allDraw.size();
+
+        if (mUseBlur) {
+            FullscreenBlur.addBlurPasses(mActiveScene, mRS, mTouchHandler.getCamera());
+        }
+
+        RenderPass mainPass = new RenderPass();
+        mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
+        mainPass.setShouldClearColor(true);
+        mainPass.setClearDepth(1.0f);
+        mainPass.setShouldClearDepth(true);
+        mainPass.setCamera(mTouchHandler.getCamera());
+        for (int i = 0; i < numDraw; i ++) {
+            mainPass.appendRenderable((Renderable)allDraw.get(i));
+        }
+        mActiveScene.appendRenderPass(mainPass);
+
+        if (mUseBlur) {
+            FullscreenBlur.addCompositePass(mActiveScene, mRS, mTouchHandler.getCamera());
+        }
+    }
+
+    private void addShadersToScene() {
+        mActiveScene.appendShader(mPaintF);
+        mActiveScene.appendShader(mLightsF);
+        mActiveScene.appendShader(mAluminumF);
+        mActiveScene.appendShader(mPlasticF);
+        mActiveScene.appendShader(mDiffuseF);
+        mActiveScene.appendShader(mTextureF);
+        mActiveScene.appendShader(mGenericV);
+    }
+
+    public void prepareToRender(Scene s) {
+        mSceneManager.setActiveScene(s);
+        mActiveScene = s;
+        mTouchHandler.init(mActiveScene);
+        addShadersToScene();
+        RenderState plastic = new RenderState(mGenericV, mPlasticF, null, null);
+        RenderState diffuse = new RenderState(mGenericV, mDiffuseF, null, null);
+        RenderState paint = new RenderState(mGenericV, mPaintF, null, null);
+        RenderState aluminum = new RenderState(mGenericV, mAluminumF, null, null);
+        RenderState lights = new RenderState(mGenericV, mLightsF, null, null);
+        RenderState glassTransp = new RenderState(mGenericV, mPaintF,
+                                                  ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS), null);
+
+        initRenderPasses();
+
+        mActiveScene.assignRenderState(plastic);
+
+        mActiveScene.assignRenderStateToMaterial(diffuse, "lambert2$");
+
+        mActiveScene.assignRenderStateToMaterial(paint, "^Paint");
+        mActiveScene.assignRenderStateToMaterial(paint, "^Carbon");
+        mActiveScene.assignRenderStateToMaterial(paint, "^Glass");
+        mActiveScene.assignRenderStateToMaterial(paint, "^MainGlass");
+
+        mActiveScene.assignRenderStateToMaterial(aluminum, "^Metal");
+        mActiveScene.assignRenderStateToMaterial(aluminum, "^Brake");
+
+        mActiveScene.assignRenderStateToMaterial(glassTransp, "^GlassLight");
+
+        mActiveScene.assignRenderStateToMaterial(lights, "^LightBlinn");
+
+        Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
+        if (plane != null) {
+            RenderState texState = new RenderState(mGenericV, mTextureF, null, null);
+            plane.setRenderState(texState);
+            plane.setVisible(!mUseBlur);
+        }
+
+        long start = System.currentTimeMillis();
+        mActiveScene.initRS();
+        long end = System.currentTimeMillis();
+        Log.v("TIMER", "Scene init time: " + (end - start));
+
+        mLoadingScreen.showLoadingScreen(false);
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
new file mode 100644
index 0000000..687f35b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+public class TestAppView extends RSSurfaceView {
+
+    public TestAppView(Context context) {
+        super(context);
+        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
+    }
+
+    private RenderScriptGL mRS;
+    TestAppRS mRender;
+
+    private ScaleGestureDetector mScaleDetector;
+    private static final int INVALID_POINTER_ID = -1;
+    private int mActivePointerId = INVALID_POINTER_ID;
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+        if (mRS == null) {
+            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+            sc.setDepth(16, 24);
+            mRS = createRenderScriptGL(sc);
+            mRS.setSurface(holder, w, h);
+            mRender = new TestAppRS();
+            mRender.init(mRS, getResources(), w, h);
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if (mRS != null) {
+            mRender = null;
+            mRS = null;
+            destroyRenderScriptGL();
+        }
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event)
+    {
+        // break point at here
+        // this method doesn't work when 'extends View' include 'extends ScrollView'.
+        return super.onKeyDown(keyCode, event);
+    }
+
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        mScaleDetector.onTouchEvent(ev);
+
+        boolean ret = false;
+        float x = ev.getX();
+        float y = ev.getY();
+
+        final int action = ev.getAction();
+
+        switch (action & MotionEvent.ACTION_MASK) {
+        case MotionEvent.ACTION_DOWN: {
+            mRender.onActionDown(x, y);
+            mActivePointerId = ev.getPointerId(0);
+            ret = true;
+            break;
+        }
+        case MotionEvent.ACTION_MOVE: {
+            if (!mScaleDetector.isInProgress()) {
+                mRender.onActionMove(x, y);
+            }
+            mRender.onActionDown(x, y);
+            ret = true;
+            break;
+        }
+
+        case MotionEvent.ACTION_UP: {
+            mActivePointerId = INVALID_POINTER_ID;
+            break;
+        }
+
+        case MotionEvent.ACTION_CANCEL: {
+            mActivePointerId = INVALID_POINTER_ID;
+            break;
+        }
+
+        case MotionEvent.ACTION_POINTER_UP: {
+            final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
+                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+            final int pointerId = ev.getPointerId(pointerIndex);
+            if (pointerId == mActivePointerId) {
+                // This was our active pointer going up. Choose a new
+                // active pointer and adjust accordingly.
+                final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+                x = ev.getX(newPointerIndex);
+                y = ev.getY(newPointerIndex);
+                mRender.onActionDown(x, y);
+                mActivePointerId = ev.getPointerId(newPointerIndex);
+            }
+            break;
+        }
+        }
+
+        return ret;
+    }
+
+    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
+        @Override
+        public boolean onScale(ScaleGestureDetector detector) {
+            mRender.onActionScale(detector.getScaleFactor());
+            return true;
+        }
+    }
+}
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
new file mode 100644
index 0000000..d8e48e8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testapp;
+
+import android.util.Log;
+import android.renderscript.Float3;
+import com.android.scenegraph.*;
+import com.android.scenegraph.CompoundTransform.RotateComponent;
+import com.android.scenegraph.CompoundTransform.TranslateComponent;
+
+public class TouchHandler {
+    private static String TAG = "TouchHandler";
+
+    float mLastX;
+    float mLastY;
+
+    float mRotateXValue;
+    float mRotateYValue;
+    Float3 mDistValue;
+    Float3 mPosValue;
+
+    CompoundTransform mCameraRig;
+    RotateComponent mRotateX;
+    RotateComponent mRotateY;
+    TranslateComponent mDist;
+    TranslateComponent mPosition;
+    Camera mCamera;
+
+    public void init(Scene scene) {
+        // Some initial values for camera position
+        mRotateXValue = -20;
+        mRotateYValue = 45;
+        mDistValue = new Float3(0, 0, 45);
+        mPosValue = new Float3(0, 4, 0);
+
+        mRotateX = new RotateComponent("RotateX", new Float3(1, 0, 0), mRotateXValue);
+        mRotateY = new RotateComponent("RotateY", new Float3(0, 1, 0), mRotateYValue);
+        mDist = new TranslateComponent("Distance", mDistValue);
+        mPosition = new TranslateComponent("Distance", mPosValue);
+
+        // Make a camera transform we can manipulate
+        mCameraRig = new CompoundTransform();
+        mCameraRig.setName("CameraRig");
+        mCameraRig.addComponent(mPosition);
+        mCameraRig.addComponent(mRotateY);
+        mCameraRig.addComponent(mRotateX);
+        mCameraRig.addComponent(mDist);
+        scene.appendTransform(mCameraRig);
+        mCamera = new Camera();
+        mCamera.setTransform(mCameraRig);
+        scene.appendCamera(mCamera);
+    }
+
+    public Camera getCamera() {
+        return mCamera;
+    }
+
+    public void onActionDown(float x, float y) {
+        mLastX = x;
+        mLastY = y;
+    }
+
+    public void onActionScale(float scale) {
+        if (mDist == null) {
+            return;
+        }
+        mDistValue.z *= 1.0f / scale;
+        mDistValue.z = Math.max(10.0f, Math.min(mDistValue.z, 150.0f));
+        mDist.setValue(mDistValue);
+    }
+
+    public void onActionMove(float x, float y) {
+        if (mRotateX == null) {
+            return;
+        }
+
+        float dx = mLastX - x;
+        float dy = mLastY - y;
+
+        if (Math.abs(dy) <= 2.0f) {
+            dy = 0.0f;
+        }
+        if (Math.abs(dx) <= 2.0f) {
+            dx = 0.0f;
+        }
+
+        mRotateYValue += dx * 0.25f;
+        mRotateYValue %= 360.0f;
+
+        mRotateXValue  += dy * 0.25f;
+        mRotateXValue  = Math.max(mRotateXValue , -80.0f);
+        mRotateXValue  = Math.min(mRotateXValue , 0.0f);
+
+        mRotateX.setAngle(mRotateXValue);
+        mRotateY.setAngle(mRotateYValue);
+
+        mLastX = x;
+        mLastY = y;
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
new file mode 100644
index 0000000..997a1a7
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
@@ -0,0 +1,86 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.testapp)
+
+#include "rs_graphics.rsh"
+#include "test_app.rsh"
+
+// Making sure these get reflected
+FBlurOffsets *blurExport;
+VShaderInputs *iExport;
+FShaderParams *fConst;
+FShaderLightParams *fConts2;
+VSParams *vConst2;
+VObjectParams *vConst3;
+
+rs_program_vertex gPVBackground;
+rs_program_fragment gPFBackground;
+
+rs_allocation gRobotTex;
+rs_mesh gRobotMesh;
+
+rs_program_store gPFSBackground;
+
+float gRotate;
+
+void init() {
+    gRotate = 0.0f;
+}
+
+static int pos = 50;
+static float gRotateY = 120.0f;
+static float3 gLookAt = 0;
+static float gZoom = 50.0f;
+static void displayLoading() {
+    if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) {
+        rsgBindProgramVertex(gPVBackground);
+        rs_matrix4x4 proj;
+        float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+        rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
+        rsgProgramVertexLoadProjectionMatrix(&proj);
+
+        rsgBindProgramFragment(gPFBackground);
+        rsgBindProgramStore(gPFSBackground);
+        rsgBindTexture(gPFBackground, 0, gRobotTex);
+
+        rs_matrix4x4 matrix;
+        rsMatrixLoadIdentity(&matrix);
+        // Position our models on the screen
+        gRotateY += rsGetDt()*100;
+        rsMatrixTranslate(&matrix, 0, 0, -gZoom);
+        rsMatrixRotate(&matrix, 20.0f, 1.0f, 0.0f, 0.0f);
+        rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
+        rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
+        rsgProgramVertexLoadModelMatrix(&matrix);
+        rsgDrawMesh(gRobotMesh);
+    }
+
+    uint width = rsgGetWidth();
+    uint height = rsgGetHeight();
+    int left = 0, right = 0, top = 0, bottom = 0;
+    const char* text = "Initializing...";
+    rsgMeasureText(text, &left, &right, &top, &bottom);
+    int centeredPos = width / 2 - (right - left) / 2;
+    rsgDrawText(text, centeredPos, height / 2 + height / 10);
+}
+
+int root(void) {
+    rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+    rsgClearDepth(1.0f);
+    displayLoading();
+    return 30;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
new file mode 100644
index 0000000..5fbcbb2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
@@ -0,0 +1,52 @@
+// Copyright (C) 2012 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.testapp)
+
+// Helpers
+typedef struct ViewProjParams {
+    rs_matrix4x4 viewProj;
+} VSParams;
+
+typedef struct ModelParams {
+    rs_matrix4x4 model;
+} VObjectParams;
+
+typedef struct CameraParams {
+    float4 cameraPos;
+} FShaderParams;
+
+typedef struct LightParams {
+    float4 lightPos_0;
+    float4 lightColor_0;
+    float4 lightPos_1;
+    float4 lightColor_1;
+    float4 cameraPos;
+    float4 diffuse;
+} FShaderLightParams;
+
+typedef struct BlurOffsets {
+    float blurOffset0;
+    float blurOffset1;
+    float blurOffset2;
+    float blurOffset3;
+} FBlurOffsets;
+
+typedef struct VertexShaderInputs {
+    float4 position;
+    float3 normal;
+    float2 texture0;
+} VShaderInputs;
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index c038478..c7bd809 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2011 The Android Open Source Project
+ * Copyright (C) 2008-2012 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.
@@ -64,14 +64,23 @@
 
         unitTests = new ArrayList<UnitTest>();
 
+        unitTests.add(new UT_mesh(this, mRes, mCtx));
+        unitTests.add(new UT_element(this, mRes, mCtx));
+        unitTests.add(new UT_sampler(this, mRes, mCtx));
+        unitTests.add(new UT_program_store(this, mRes, mCtx));
+        unitTests.add(new UT_program_raster(this, mRes, mCtx));
         unitTests.add(new UT_primitives(this, mRes, mCtx));
+        unitTests.add(new UT_constant(this, mRes, mCtx));
         unitTests.add(new UT_vector(this, mRes, mCtx));
+        unitTests.add(new UT_array_init(this, mRes, mCtx));
         unitTests.add(new UT_rsdebug(this, mRes, mCtx));
         unitTests.add(new UT_rstime(this, mRes, mCtx));
         unitTests.add(new UT_rstypes(this, mRes, mCtx));
         unitTests.add(new UT_alloc(this, mRes, mCtx));
         unitTests.add(new UT_refcount(this, mRes, mCtx));
         unitTests.add(new UT_foreach(this, mRes, mCtx));
+        unitTests.add(new UT_atomic(this, mRes, mCtx));
+        unitTests.add(new UT_struct(this, mRes, mCtx));
         unitTests.add(new UT_math(this, mRes, mCtx));
         unitTests.add(new UT_fp_mad(this, mRes, mCtx));
         /*
@@ -91,7 +100,7 @@
         for (int i = 0; i < uta.length; i++) {
             ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
             listElem.text = Allocation.createFromString(mRS, uta[i].name, Allocation.USAGE_SCRIPT);
-            listElem.result = uta[i].result;
+            listElem.result = uta[i].getResult();
             mListAllocs.set(listElem, i, false);
             uta[i].setItem(listElem);
         }
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java
new file mode 100644
index 0000000..b98b753
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_array_init extends UnitTest {
+    private Resources mRes;
+
+    protected UT_array_init(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Array Init", ctx);
+        mRes = res;
+    }
+
+    private void checkInit(ScriptC_array_init s) {
+        float[] fa = s.get_fa();
+        _RS_ASSERT("fa[0] == 1.0", fa[0] == 1.0);
+        _RS_ASSERT("fa[1] == 9.9999f", fa[1] == 9.9999f);
+        _RS_ASSERT("fa[2] == 0", fa[2] == 0);
+        _RS_ASSERT("fa[3] == 0", fa[3] == 0);
+        _RS_ASSERT("fa.length == 4", fa.length == 4);
+
+        double[] da = s.get_da();
+        _RS_ASSERT("da[0] == 7.0", da[0] == 7.0);
+        _RS_ASSERT("da[1] == 8.88888", da[1] == 8.88888);
+        _RS_ASSERT("da.length == 2", da.length == 2);
+
+        byte[] ca = s.get_ca();
+        _RS_ASSERT("ca[0] == 'a'", ca[0] == 'a');
+        _RS_ASSERT("ca[1] == 7", ca[1] == 7);
+        _RS_ASSERT("ca[2] == 'b'", ca[2] == 'b');
+        _RS_ASSERT("ca[3] == 'c'", ca[3] == 'c');
+        _RS_ASSERT("ca.length == 4", ca.length == 4);
+
+        short[] sa = s.get_sa();
+        _RS_ASSERT("sa[0] == 1", sa[0] == 1);
+        _RS_ASSERT("sa[1] == 1", sa[1] == 1);
+        _RS_ASSERT("sa[2] == 2", sa[2] == 2);
+        _RS_ASSERT("sa[3] == 3", sa[3] == 3);
+        _RS_ASSERT("sa.length == 4", sa.length == 4);
+
+        int[] ia = s.get_ia();
+        _RS_ASSERT("ia[0] == 5", ia[0] == 5);
+        _RS_ASSERT("ia[1] == 8", ia[1] == 8);
+        _RS_ASSERT("ia[2] == 0", ia[2] == 0);
+        _RS_ASSERT("ia[3] == 0", ia[3] == 0);
+        _RS_ASSERT("ia.length == 4", ia.length == 4);
+
+        long[] la = s.get_la();
+        _RS_ASSERT("la[0] == 13", la[0] == 13);
+        _RS_ASSERT("la[1] == 21", la[1] == 21);
+        _RS_ASSERT("la.length == 4", la.length == 2);
+
+        long[] lla = s.get_lla();
+        _RS_ASSERT("lla[0] == 34", lla[0] == 34);
+        _RS_ASSERT("lla[1] == 0", lla[1] == 0);
+        _RS_ASSERT("lla[2] == 0", lla[2] == 0);
+        _RS_ASSERT("lla[3] == 0", lla[3] == 0);
+        _RS_ASSERT("lla.length == 4", lla.length == 4);
+
+        boolean[] ba = s.get_ba();
+        _RS_ASSERT("ba[0] == true", ba[0] == true);
+        _RS_ASSERT("ba[1] == false", ba[1] == false);
+        _RS_ASSERT("ba[2] == false", ba[2] == false);
+        _RS_ASSERT("ba.length == 3", ba.length == 3);
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_array_init s = new ScriptC_array_init(pRS, mRes, R.raw.array_init);
+        pRS.setMessageHandler(mRsMessage);
+        checkInit(s);
+        s.invoke_array_init_test();
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+        passTest();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java
new file mode 100644
index 0000000..267c5b2
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_atomic extends UnitTest {
+    private Resources mRes;
+
+    protected UT_atomic(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Atomics", ctx);
+        mRes = res;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_atomic s = new ScriptC_atomic(pRS, mRes, R.raw.atomic);
+        pRS.setMessageHandler(mRsMessage);
+        s.invoke_atomic_test();
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java
new file mode 100644
index 0000000..adda5a3
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_constant extends UnitTest {
+    private Resources mRes;
+
+    protected UT_constant(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Const", ctx);
+        mRes = res;
+    }
+
+    private void Assert(boolean b) {
+        if (!b) {
+            failTest();
+        }
+    }
+
+    public void run() {
+        Assert(ScriptC_constant.const_floatTest == 1.99f);
+        Assert(ScriptC_constant.const_doubleTest == 2.05);
+        Assert(ScriptC_constant.const_charTest == -8);
+        Assert(ScriptC_constant.const_shortTest == -16);
+        Assert(ScriptC_constant.const_intTest == -32);
+        Assert(ScriptC_constant.const_longTest == 17179869184l);
+        Assert(ScriptC_constant.const_longlongTest == 68719476736l);
+
+        Assert(ScriptC_constant.const_ucharTest == 8);
+        Assert(ScriptC_constant.const_ushortTest == 16);
+        Assert(ScriptC_constant.const_uintTest == 32);
+        Assert(ScriptC_constant.const_ulongTest == 4611686018427387904L);
+        Assert(ScriptC_constant.const_int64_tTest == -17179869184l);
+        Assert(ScriptC_constant.const_uint64_tTest == 117179869184l);
+
+        Assert(ScriptC_constant.const_boolTest == true);
+
+        passTest();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
new file mode 100644
index 0000000..3e2a2ca
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Element.*;
+import android.renderscript.Element.DataKind.*;
+import android.renderscript.Element.DataType.*;
+
+public class UT_element extends UnitTest {
+    private Resources mRes;
+
+    Element simpleElem;
+    Element complexElem;
+
+    final String subElemNames[] = {
+        "subElem0",
+        "subElem1",
+        "subElem2",
+        "arrayElem0",
+        "arrayElem1",
+        "subElem3",
+        "subElem4",
+        "subElem5",
+        "subElem6",
+        "subElem_7",
+    };
+
+    final int subElemArraySizes[] = {
+        1,
+        1,
+        1,
+        2,
+        5,
+        1,
+        1,
+        1,
+        1,
+        1,
+    };
+
+    final int subElemOffsets[] = {
+        0,
+        4,
+        8,
+        12,
+        20,
+        40,
+        44,
+        48,
+        64,
+        80,
+    };
+
+    protected UT_element(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Element", ctx);
+        mRes = res;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_element s) {
+        simpleElem = Element.F32_3(RS);
+        complexElem = ScriptField_ComplexStruct.createElement(RS);
+        s.set_simpleElem(simpleElem);
+        s.set_complexElem(complexElem);
+
+        ScriptField_ComplexStruct data = new ScriptField_ComplexStruct(RS, 1);
+        s.bind_complexStruct(data);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_element s = new ScriptC_element(pRS, mRes, R.raw.element);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_element_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+
+        int subElemCount = simpleElem.getSubElementCount();
+        _RS_ASSERT("subElemCount == 0", subElemCount == 0);
+        _RS_ASSERT("simpleElem.getDataKind() == USER",
+                   simpleElem.getDataKind() == DataKind.USER);
+        _RS_ASSERT("simpleElem.getDataType() == FLOAT_32",
+                   simpleElem.getDataType() == DataType.FLOAT_32);
+
+        subElemCount = complexElem.getSubElementCount();
+        _RS_ASSERT("subElemCount == 10", subElemCount == 10);
+        _RS_ASSERT("complexElem.getDataKind() == USER",
+                   complexElem.getDataKind() == DataKind.USER);
+        _RS_ASSERT("complexElemsimpleElem.getDataType() == NONE",
+                   complexElem.getDataType() == DataType.NONE);
+        _RS_ASSERT("complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof",
+                   complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof);
+
+        for (int i = 0; i < subElemCount; i ++) {
+            _RS_ASSERT("complexElem.getSubElement(i) != null",
+                       complexElem.getSubElement(i) != null);
+            _RS_ASSERT("complexElem.getSubElementName(i).equals(subElemNames[i])",
+                       complexElem.getSubElementName(i).equals(subElemNames[i]));
+            _RS_ASSERT("complexElem.getSubElementArraySize(i) == subElemArraySizes[i]",
+                       complexElem.getSubElementArraySize(i) == subElemArraySizes[i]);
+            _RS_ASSERT("complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]",
+                       complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]);
+        }
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        passTest();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
new file mode 100644
index 0000000..0c93702
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Mesh.*;
+
+public class UT_mesh extends UnitTest {
+    private Resources mRes;
+
+    Mesh mesh;
+
+    protected UT_mesh(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Mesh", ctx);
+        mRes = res;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_mesh s) {
+        Allocation vAlloc0 = Allocation.createSized(RS, Element.F32(RS), 10);
+        Allocation vAlloc1 = Allocation.createSized(RS, Element.F32_2(RS), 10);
+
+        Allocation iAlloc0 = Allocation.createSized(RS, Element.I16(RS), 10);
+        Allocation iAlloc2 = Allocation.createSized(RS, Element.I16(RS), 10);
+
+        Mesh.AllocationBuilder mBuilder = new Mesh.AllocationBuilder(RS);
+        mBuilder.addVertexAllocation(vAlloc0);
+        mBuilder.addVertexAllocation(vAlloc1);
+
+        mBuilder.addIndexSetAllocation(iAlloc0, Primitive.POINT);
+        mBuilder.addIndexSetType(Primitive.LINE);
+        mBuilder.addIndexSetAllocation(iAlloc2, Primitive.TRIANGLE);
+
+        s.set_mesh(mBuilder.create());
+        s.set_vertexAlloc0(vAlloc0);
+        s.set_vertexAlloc1(vAlloc1);
+        s.set_indexAlloc0(iAlloc0);
+        s.set_indexAlloc2(iAlloc2);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_mesh s = new ScriptC_mesh(pRS, mRes, R.raw.mesh);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_mesh_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        passTest();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
index b7a65a5..18829c2 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
@@ -92,8 +92,7 @@
         ScriptC_primitives s = new ScriptC_primitives(pRS, mRes, R.raw.primitives);
         pRS.setMessageHandler(mRsMessage);
         if (!initializeGlobals(s)) {
-            // initializeGlobals failed
-            result = -1;
+            failTest();
         } else {
             s.invoke_primitives_test(0, 0);
             pRS.finish();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
new file mode 100644
index 0000000..1de4d71
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramRaster.CullMode;
+
+public class UT_program_raster extends UnitTest {
+    private Resources mRes;
+
+    ProgramRaster pointSpriteEnabled;
+    ProgramRaster cullMode;
+
+    protected UT_program_raster(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "ProgramRaster", ctx);
+        mRes = res;
+    }
+
+    private ProgramRaster.Builder getDefaultBuilder(RenderScript RS) {
+        ProgramRaster.Builder b = new ProgramRaster.Builder(RS);
+        b.setCullMode(CullMode.BACK);
+        b.setPointSpriteEnabled(false);
+        return b;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_program_raster s) {
+        ProgramRaster.Builder b = getDefaultBuilder(RS);
+        pointSpriteEnabled = b.setPointSpriteEnabled(true).create();
+        b = getDefaultBuilder(RS);
+        cullMode = b.setCullMode(CullMode.FRONT).create();
+
+        s.set_pointSpriteEnabled(pointSpriteEnabled);
+        s.set_cullMode(cullMode);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_program_raster s = new ScriptC_program_raster(pRS, mRes, R.raw.program_raster);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_program_raster_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+        _RS_ASSERT("pointSpriteEnabled.getPointSpriteEnabled() == true",
+                    pointSpriteEnabled.getPointSpriteEnabled() == true);
+        _RS_ASSERT("pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK",
+                    pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK);
+
+        _RS_ASSERT("cullMode.getPointSpriteEnabled() == false",
+                    cullMode.getPointSpriteEnabled() == false);
+        _RS_ASSERT("cullMode.getCullMode() == ProgramRaster.CullMode.FRONT",
+                    cullMode.getCullMode() == ProgramRaster.CullMode.FRONT);
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        passTest();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
new file mode 100644
index 0000000..72a401d
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.BlendDstFunc;
+import android.renderscript.ProgramStore.BlendSrcFunc;
+import android.renderscript.ProgramStore.Builder;
+import android.renderscript.ProgramStore.DepthFunc;
+
+public class UT_program_store extends UnitTest {
+    private Resources mRes;
+
+    ProgramStore ditherEnable;
+    ProgramStore colorRWriteEnable;
+    ProgramStore colorGWriteEnable;
+    ProgramStore colorBWriteEnable;
+    ProgramStore colorAWriteEnable;
+    ProgramStore blendSrc;
+    ProgramStore blendDst;
+    ProgramStore depthWriteEnable;
+    ProgramStore depthFunc;
+
+    protected UT_program_store(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "ProgramStore", ctx);
+        mRes = res;
+    }
+
+    private ProgramStore.Builder getDefaultBuilder(RenderScript RS) {
+        ProgramStore.Builder b = new ProgramStore.Builder(RS);
+        b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO, ProgramStore.BlendDstFunc.ZERO);
+        b.setColorMaskEnabled(false, false, false, false);
+        b.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+        b.setDepthMaskEnabled(false);
+        b.setDitherEnabled(false);
+        return b;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_program_store s) {
+        ProgramStore.Builder b = getDefaultBuilder(RS);
+        ditherEnable = b.setDitherEnabled(true).create();
+
+        b = getDefaultBuilder(RS);
+        colorRWriteEnable = b.setColorMaskEnabled(true,  false, false, false).create();
+
+        b = getDefaultBuilder(RS);
+        colorGWriteEnable = b.setColorMaskEnabled(false, true,  false, false).create();
+
+        b = getDefaultBuilder(RS);
+        colorBWriteEnable = b.setColorMaskEnabled(false, false, true,  false).create();
+
+        b = getDefaultBuilder(RS);
+        colorAWriteEnable = b.setColorMaskEnabled(false, false, false, true).create();
+
+        b = getDefaultBuilder(RS);
+        blendSrc = b.setBlendFunc(ProgramStore.BlendSrcFunc.DST_COLOR,
+                                  ProgramStore.BlendDstFunc.ZERO).create();
+
+        b = getDefaultBuilder(RS);
+        blendDst = b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO,
+                                  ProgramStore.BlendDstFunc.DST_ALPHA).create();
+
+        b = getDefaultBuilder(RS);
+        depthWriteEnable = b.setDepthMaskEnabled(true).create();
+
+        b = getDefaultBuilder(RS);
+        depthFunc = b.setDepthFunc(ProgramStore.DepthFunc.GREATER).create();
+
+        s.set_ditherEnable(ditherEnable);
+        s.set_colorRWriteEnable(colorRWriteEnable);
+        s.set_colorGWriteEnable(colorGWriteEnable);
+        s.set_colorBWriteEnable(colorBWriteEnable);
+        s.set_colorAWriteEnable(colorAWriteEnable);
+        s.set_blendSrc(blendSrc);
+        s.set_blendDst(blendDst);
+        s.set_depthWriteEnable(depthWriteEnable);
+        s.set_depthFunc(depthFunc);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_program_store s = new ScriptC_program_store(pRS, mRes, R.raw.program_store);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_program_store_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    void checkObject(ProgramStore ps,
+                     boolean depthMask,
+                     DepthFunc df,
+                     BlendSrcFunc bsf,
+                     BlendDstFunc bdf,
+                     boolean R,
+                     boolean G,
+                     boolean B,
+                     boolean A,
+                     boolean dither) {
+        _RS_ASSERT("ps.getDepthMaskEnabled() == depthMask", ps.getDepthMaskEnabled() == depthMask);
+        _RS_ASSERT("ps.getDepthFunc() == df", ps.getDepthFunc() == df);
+        _RS_ASSERT("ps.getBlendSrcFunc() == bsf", ps.getBlendSrcFunc() == bsf);
+        _RS_ASSERT("ps.getBlendDstFunc() == bdf", ps.getBlendDstFunc() == bdf);
+        _RS_ASSERT("ps.getColorMaskREnabled() == R", ps.getColorMaskREnabled() == R);
+        _RS_ASSERT("ps.getColorMaskGEnabled() == G", ps.getColorMaskGEnabled() == G);
+        _RS_ASSERT("ps.getColorMaskBEnabled() == B", ps.getColorMaskBEnabled() == B);
+        _RS_ASSERT("ps.getColorMaskAEnabled() == A", ps.getColorMaskAEnabled() == A);
+        _RS_ASSERT("ps.getDitherEnabled() == dither", ps.getDitherEnabled() == dither);
+    }
+
+    void varyBuilderColorAndDither(ProgramStore.Builder pb,
+                                   boolean depthMask,
+                                   DepthFunc df,
+                                   BlendSrcFunc bsf,
+                                   BlendDstFunc bdf) {
+        for (int r = 0; r <= 1; r++) {
+            boolean isR = (r == 1);
+            for (int g = 0; g <= 1; g++) {
+                boolean isG = (g == 1);
+                for (int b = 0; b <= 1; b++) {
+                    boolean isB = (b == 1);
+                    for (int a = 0; a <= 1; a++) {
+                        boolean isA = (a == 1);
+                        for (int dither = 0; dither <= 1; dither++) {
+                            boolean isDither = (dither == 1);
+                            pb.setDitherEnabled(isDither);
+                            pb.setColorMaskEnabled(isR, isG, isB, isA);
+                            ProgramStore ps = pb.create();
+                            checkObject(ps, depthMask, df, bsf, bdf, isR, isG, isB, isA, isDither);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void testJavaSide(RenderScript RS) {
+        for (int depth = 0; depth <= 1; depth++) {
+            boolean depthMask = (depth == 1);
+            for (DepthFunc df : DepthFunc.values()) {
+                for (BlendSrcFunc bsf : BlendSrcFunc.values()) {
+                    for (BlendDstFunc bdf : BlendDstFunc.values()) {
+                        ProgramStore.Builder b = new ProgramStore.Builder(RS);
+                        b.setDepthFunc(df);
+                        b.setDepthMaskEnabled(depthMask);
+                        b.setBlendFunc(bsf, bdf);
+                        varyBuilderColorAndDither(b, depthMask, df, bsf, bdf);
+                    }
+                }
+            }
+        }
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testJavaSide(pRS);
+        testScriptSide(pRS);
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
new file mode 100644
index 0000000..c328cf6
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Sampler;
+import android.renderscript.Sampler.Value;
+
+public class UT_sampler extends UnitTest {
+    private Resources mRes;
+
+    Sampler minification;
+    Sampler magnification;
+    Sampler wrapS;
+    Sampler wrapT;
+    Sampler anisotropy;
+
+    protected UT_sampler(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Sampler", ctx);
+        mRes = res;
+    }
+
+    private Sampler.Builder getDefaultBuilder(RenderScript RS) {
+        Sampler.Builder b = new Sampler.Builder(RS);
+        b.setMinification(Value.NEAREST);
+        b.setMagnification(Value.NEAREST);
+        b.setWrapS(Value.CLAMP);
+        b.setWrapT(Value.CLAMP);
+        b.setAnisotropy(1.0f);
+        return b;
+    }
+
+    private void initializeGlobals(RenderScript RS, ScriptC_sampler s) {
+        Sampler.Builder b = getDefaultBuilder(RS);
+        b.setMinification(Value.LINEAR_MIP_LINEAR);
+        minification = b.create();
+
+        b = getDefaultBuilder(RS);
+        b.setMagnification(Value.LINEAR);
+        magnification = b.create();
+
+        b = getDefaultBuilder(RS);
+        b.setWrapS(Value.WRAP);
+        wrapS = b.create();
+
+        b = getDefaultBuilder(RS);
+        b.setWrapT(Value.WRAP);
+        wrapT = b.create();
+
+        b = getDefaultBuilder(RS);
+        b.setAnisotropy(8.0f);
+        anisotropy = b.create();
+
+        s.set_minification(minification);
+        s.set_magnification(magnification);
+        s.set_wrapS(wrapS);
+        s.set_wrapT(wrapT);
+        s.set_anisotropy(anisotropy);
+    }
+
+    private void testScriptSide(RenderScript pRS) {
+        ScriptC_sampler s = new ScriptC_sampler(pRS, mRes, R.raw.sampler);
+        pRS.setMessageHandler(mRsMessage);
+        initializeGlobals(pRS, s);
+        s.invoke_sampler_test();
+        pRS.finish();
+        waitForMessage();
+    }
+
+    private void testJavaSide(RenderScript RS) {
+        _RS_ASSERT("minification.getMagnification() == Sampler.Value.NEAREST",
+                    minification.getMagnification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR",
+                    minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR);
+        _RS_ASSERT("minification.getWrapS() == Sampler.Value.CLAMP",
+                    minification.getWrapS() == Sampler.Value.CLAMP);
+        _RS_ASSERT("minification.getWrapT() == Sampler.Value.CLAMP",
+                    minification.getWrapT() == Sampler.Value.CLAMP);
+        _RS_ASSERT("minification.getAnisotropy() == 1.0f",
+                    minification.getAnisotropy() == 1.0f);
+
+        _RS_ASSERT("magnification.getMagnification() == Sampler.Value.LINEAR",
+                    magnification.getMagnification() == Sampler.Value.LINEAR);
+        _RS_ASSERT("magnification.getMinification() == Sampler.Value.NEAREST",
+                    magnification.getMinification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("magnification.getWrapS() == Sampler.Value.CLAMP",
+                    magnification.getWrapS() == Sampler.Value.CLAMP);
+        _RS_ASSERT("magnification.getWrapT() == Sampler.Value.CLAMP",
+                    magnification.getWrapT() == Sampler.Value.CLAMP);
+        _RS_ASSERT("magnification.getAnisotropy() == 1.0f",
+                    magnification.getAnisotropy() == 1.0f);
+
+        _RS_ASSERT("wrapS.getMagnification() == Sampler.Value.NEAREST",
+                    wrapS.getMagnification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("wrapS.getMinification() == Sampler.Value.NEAREST",
+                    wrapS.getMinification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("wrapS.getWrapS() == Sampler.Value.WRAP",
+                    wrapS.getWrapS() == Sampler.Value.WRAP);
+        _RS_ASSERT("wrapS.getWrapT() == Sampler.Value.CLAMP",
+                    wrapS.getWrapT() == Sampler.Value.CLAMP);
+        _RS_ASSERT("wrapS.getAnisotropy() == 1.0f",
+                    wrapS.getAnisotropy() == 1.0f);
+
+        _RS_ASSERT("wrapT.getMagnification() == Sampler.Value.NEAREST",
+                    wrapT.getMagnification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("wrapT.getMinification() == Sampler.Value.NEAREST",
+                    wrapT.getMinification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("wrapT.getWrapS() == Sampler.Value.CLAMP",
+                    wrapT.getWrapS() == Sampler.Value.CLAMP);
+        _RS_ASSERT("wrapT.getWrapT() == Sampler.Value.WRAP",
+                    wrapT.getWrapT() == Sampler.Value.WRAP);
+        _RS_ASSERT("wrapT.getAnisotropy() == 1.0f",
+                    wrapT.getAnisotropy() == 1.0f);
+
+        _RS_ASSERT("anisotropy.getMagnification() == Sampler.Value.NEAREST",
+                    anisotropy.getMagnification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("anisotropy.getMinification() == Sampler.Value.NEAREST",
+                    anisotropy.getMinification() == Sampler.Value.NEAREST);
+        _RS_ASSERT("anisotropy.getWrapS() == Sampler.Value.CLAMP",
+                    anisotropy.getWrapS() == Sampler.Value.CLAMP);
+        _RS_ASSERT("anisotropy.getWrapT() == Sampler.Value.CLAMP",
+                    anisotropy.getWrapT() == Sampler.Value.CLAMP);
+        _RS_ASSERT("anisotropy.getAnisotropy() == 1.0f",
+                    anisotropy.getAnisotropy() == 8.0f);
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        testScriptSide(pRS);
+        testJavaSide(pRS);
+        passTest();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java
new file mode 100644
index 0000000..2a55686
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_struct extends UnitTest {
+    private Resources mRes;
+
+    protected UT_struct(RSTestCore rstc, Resources res, Context ctx) {
+        super(rstc, "Struct", ctx);
+        mRes = res;
+    }
+
+    public void run() {
+        RenderScript pRS = RenderScript.create(mCtx);
+        ScriptC_struct s = new ScriptC_struct(pRS, mRes, R.raw.struct);
+        pRS.setMessageHandler(mRsMessage);
+
+        ScriptField_Point2 p = new ScriptField_Point2(pRS, 1);
+        ScriptField_Point2.Item i = new ScriptField_Point2.Item();
+        int val = 100;
+        i.x = val;
+        i.y = val;
+        p.set(i, 0, true);
+        s.bind_point2(p);
+        s.invoke_struct_test(val);
+        pRS.finish();
+        waitForMessage();
+
+        val = 200;
+        p.set_x(0, val, true);
+        p.set_y(0, val, true);
+        s.invoke_struct_test(val);
+        pRS.finish();
+        waitForMessage();
+        pRS.destroy();
+    }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
index 748701d..0ac09ca 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
@@ -307,7 +307,7 @@
         ScriptC_vector s = new ScriptC_vector(pRS, mRes, R.raw.vector);
         pRS.setMessageHandler(mRsMessage);
         if (!initializeGlobals(s)) {
-            result = -1;
+            failTest();
         } else {
             s.invoke_vector_test();
             pRS.finish();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
index a97ffa7..fbac124 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
@@ -21,7 +21,7 @@
 
 public class UnitTest extends Thread {
     public String name;
-    public int result;
+    private int result;
     private ScriptField_ListAllocs_s.Item mItem;
     private RSTestCore mRSTC;
     private boolean msgHandled;
@@ -58,12 +58,12 @@
 
     protected void _RS_ASSERT(String message, boolean b) {
         if(b == false) {
-            result = -1;
             Log.e(name, message + " FAILED");
+            failTest();
         }
     }
 
-    protected void updateUI() {
+    private void updateUI() {
         if (mItem != null) {
             mItem.result = result;
             msgHandled = true;
@@ -104,6 +104,22 @@
         }
     }
 
+    public int getResult() {
+        return result;
+    }
+
+    public void failTest() {
+        result = -1;
+        updateUI();
+    }
+
+    public void passTest() {
+        if (result != -1) {
+            result = 1;
+        }
+        updateUI();
+    }
+
     public void setItem(ScriptField_ListAllocs_s.Item item) {
         mItem = item;
     }
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs
new file mode 100644
index 0000000..842249a
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs
@@ -0,0 +1,58 @@
+#include "shared.rsh"
+
+// Testing constant array initialization
+float fa[4] = {1.0, 9.9999f};
+double da[2] = {7.0, 8.88888};
+char ca[4] = {'a', 7, 'b', 'c'};
+short sa[4] = {1, 1, 2, 3};
+int ia[4] = {5, 8};
+long la[2] = {13, 21};
+long long lla[4] = {34};
+bool ba[3] = {true, false};
+
+void array_init_test() {
+    bool failed = false;
+
+    _RS_ASSERT(fa[0] == 1.0);
+    _RS_ASSERT(fa[1] == 9.9999f);
+    _RS_ASSERT(fa[2] == 0);
+    _RS_ASSERT(fa[3] == 0);
+
+    _RS_ASSERT(da[0] == 7.0);
+    _RS_ASSERT(da[1] == 8.88888);
+
+    _RS_ASSERT(ca[0] == 'a');
+    _RS_ASSERT(ca[1] == 7);
+    _RS_ASSERT(ca[2] == 'b');
+    _RS_ASSERT(ca[3] == 'c');
+
+    _RS_ASSERT(sa[0] == 1);
+    _RS_ASSERT(sa[1] == 1);
+    _RS_ASSERT(sa[2] == 2);
+    _RS_ASSERT(sa[3] == 3);
+
+    _RS_ASSERT(ia[0] == 5);
+    _RS_ASSERT(ia[1] == 8);
+    _RS_ASSERT(ia[2] == 0);
+    _RS_ASSERT(ia[3] == 0);
+
+    _RS_ASSERT(la[0] == 13);
+    _RS_ASSERT(la[1] == 21);
+
+    _RS_ASSERT(lla[0] == 34);
+    _RS_ASSERT(lla[1] == 0);
+    _RS_ASSERT(lla[2] == 0);
+    _RS_ASSERT(lla[3] == 0);
+
+    _RS_ASSERT(ba[0] == true);
+    _RS_ASSERT(ba[1] == false);
+    _RS_ASSERT(ba[2] == false);
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs
new file mode 100644
index 0000000..f0a5041
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs
@@ -0,0 +1,77 @@
+#include "shared.rsh"
+
+// Testing atomic operations
+static bool testUMax(uint32_t dst, uint32_t src) {
+    bool failed = false;
+    uint32_t old = dst;
+    uint32_t expect = (dst > src ? dst : src);
+    uint32_t ret = rsAtomicMax(&dst, src);
+    _RS_ASSERT(old == ret);
+    _RS_ASSERT(dst == expect);
+    return failed;
+}
+
+static bool testUMin(uint32_t dst, uint32_t src) {
+    bool failed = false;
+    uint32_t old = dst;
+    uint32_t expect = (dst < src ? dst : src);
+    uint32_t ret = rsAtomicMin(&dst, src);
+    _RS_ASSERT(old == ret);
+    _RS_ASSERT(dst == expect);
+    return failed;
+}
+
+static bool testUCas(uint32_t dst, uint32_t cmp, uint32_t swp) {
+    bool failed = false;
+    uint32_t old = dst;
+    uint32_t expect = (dst == cmp ? swp : dst);
+    uint32_t ret = rsAtomicCas(&dst, cmp, swp);
+    _RS_ASSERT(old == ret);
+    _RS_ASSERT(dst == expect);
+    return failed;
+}
+
+static bool test_atomics() {
+    bool failed = false;
+
+    failed |= testUMax(5, 6);
+    failed |= testUMax(6, 5);
+    failed |= testUMax(5, 0xf0000006);
+    failed |= testUMax(0xf0000006, 5);
+
+    failed |= testUMin(5, 6);
+    failed |= testUMin(6, 5);
+    failed |= testUMin(5, 0xf0000006);
+    failed |= testUMin(0xf0000006, 5);
+
+    failed |= testUCas(4, 4, 5);
+    failed |= testUCas(4, 5, 5);
+    failed |= testUCas(5, 5, 4);
+    failed |= testUCas(5, 4, 4);
+    failed |= testUCas(0xf0000004, 0xf0000004, 0xf0000005);
+    failed |= testUCas(0xf0000004, 0xf0000005, 0xf0000005);
+    failed |= testUCas(0xf0000005, 0xf0000005, 0xf0000004);
+    failed |= testUCas(0xf0000005, 0xf0000004, 0xf0000004);
+
+    if (failed) {
+        rsDebug("test_atomics FAILED", 0);
+    }
+    else {
+        rsDebug("test_atomics PASSED", 0);
+    }
+
+    return failed;
+}
+
+void atomic_test() {
+    bool failed = false;
+    failed |= test_atomics();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs
new file mode 100644
index 0000000..732eaef
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs
@@ -0,0 +1,19 @@
+#include "shared.rsh"
+
+const float floatTest = 1.99f;
+const double doubleTest = 2.05;
+const char charTest = -8;
+const short shortTest = -16;
+const int intTest = -32;
+const long longTest = 17179869184l; // 1 << 34
+const long long longlongTest = 68719476736l; // 1 << 36
+
+const uchar ucharTest = 8;
+const ushort ushortTest = 16;
+const uint uintTest = 32;
+const ulong ulongTest = 4611686018427387904L;
+const int64_t int64_tTest = -17179869184l; // - 1 << 34
+const uint64_t uint64_tTest = 117179869184l;
+
+const bool boolTest = true;
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
new file mode 100644
index 0000000..0c42d84
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
@@ -0,0 +1,158 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_element simpleElem;
+rs_element complexElem;
+typedef struct ComplexStruct {
+    float subElem0;
+    float subElem1;
+    int subElem2;
+    float arrayElem0[2];
+    int arrayElem1[5];
+    char subElem3;
+    float subElem4;
+    float2 subElem5;
+    float3 subElem6;
+    float4 subElem_7;
+} ComplexStruct_t;
+
+ComplexStruct_t *complexStruct;
+
+static const char *subElemNames[] = {
+    "subElem0",
+    "subElem1",
+    "subElem2",
+    "arrayElem0",
+    "arrayElem1",
+    "subElem3",
+    "subElem4",
+    "subElem5",
+    "subElem6",
+    "subElem_7",
+};
+
+static uint32_t subElemNamesSizes[] = {
+    8,
+    8,
+    8,
+    10,
+    10,
+    8,
+    8,
+    8,
+    8,
+    9,
+};
+
+static uint32_t subElemArraySizes[] = {
+    1,
+    1,
+    1,
+    2,
+    5,
+    1,
+    1,
+    1,
+    1,
+    1,
+};
+
+static void resetStruct() {
+    uint8_t *bytePtr = (uint8_t*)complexStruct;
+    uint32_t sizeOfStruct = sizeof(*complexStruct);
+    for(uint32_t i = 0; i < sizeOfStruct; i ++) {
+        bytePtr[i] = 0;
+    }
+}
+
+static bool equals(const char *name0, const char * name1, uint32_t len) {
+    for (uint32_t i = 0; i < len; i ++) {
+        if (name0[i] != name1[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool test_element_getters() {
+    bool failed = false;
+
+    uint32_t subElemOffsets[10];
+    uint32_t index = 0;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem0   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem1   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem2   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem0 - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem1 - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem3   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem4   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem5   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem6   - (uint32_t)complexStruct;
+    subElemOffsets[index++] = (uint32_t)&complexStruct->subElem_7  - (uint32_t)complexStruct;
+
+    uint32_t subElemCount = rsElementGetSubElementCount(simpleElem);
+    _RS_ASSERT(subElemCount == 0);
+    _RS_ASSERT(rsElementGetDataKind(simpleElem) == RS_KIND_USER);
+    _RS_ASSERT(rsElementGetDataType(simpleElem) == RS_TYPE_FLOAT_32);
+    _RS_ASSERT(rsElementGetVectorSize(simpleElem) == 3);
+
+    subElemCount = rsElementGetSubElementCount(complexElem);
+    _RS_ASSERT(subElemCount == 10);
+    _RS_ASSERT(rsElementGetDataKind(complexElem) == RS_KIND_USER);
+    _RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE);
+    _RS_ASSERT(rsElementGetVectorSize(complexElem) == 1);
+    _RS_ASSERT(rsElementGetSizeBytes(complexElem) == sizeof(*complexStruct));
+
+    char buffer[64];
+    for (uint32_t i = 0; i < subElemCount; i ++) {
+        rs_element subElem = rsElementGetSubElement(complexElem, i);
+        _RS_ASSERT(rsIsObject(subElem));
+
+        _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, i) == subElemNamesSizes[i] + 1);
+
+        uint32_t written = rsElementGetSubElementName(complexElem, i, buffer, 64);
+        _RS_ASSERT(written == subElemNamesSizes[i]);
+        _RS_ASSERT(equals(buffer, subElemNames[i], written));
+
+        _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, i) == subElemArraySizes[i]);
+        _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, i) == subElemOffsets[i]);
+    }
+
+    // Tests error checking
+    rs_element subElem = rsElementGetSubElement(complexElem, subElemCount);
+    _RS_ASSERT(!rsIsObject(subElem));
+
+    _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, subElemCount) == 0);
+
+    _RS_ASSERT(rsElementGetSubElementName(complexElem, subElemCount, buffer, 64) == 0);
+    _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, NULL, 64) == 0);
+    _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, buffer, 0) == 0);
+    uint32_t written = rsElementGetSubElementName(complexElem, 0, buffer, 5);
+    _RS_ASSERT(written == 4);
+    _RS_ASSERT(buffer[4] == '\0');
+
+    _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, subElemCount) == 0);
+    _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, subElemCount) == 0);
+
+    if (failed) {
+        rsDebug("test_element_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_element_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void element_test() {
+    bool failed = false;
+    failed |= test_element_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
new file mode 100644
index 0000000..627ab99
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
@@ -0,0 +1,64 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_mesh mesh;
+rs_allocation vertexAlloc0;
+rs_allocation vertexAlloc1;
+
+rs_allocation indexAlloc0;
+rs_allocation indexAlloc2;
+
+static bool test_mesh_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsMeshGetVertexAllocationCount(mesh) == 2);
+    _RS_ASSERT(rsMeshGetPrimitiveCount(mesh) == 3);
+
+    rs_allocation meshV0 = rsMeshGetVertexAllocation(mesh, 0);
+    rs_allocation meshV1 = rsMeshGetVertexAllocation(mesh, 1);
+    rs_allocation meshV2 = rsMeshGetVertexAllocation(mesh, 2);
+    _RS_ASSERT(meshV0.p == vertexAlloc0.p);
+    _RS_ASSERT(meshV1.p == vertexAlloc1.p);
+    _RS_ASSERT(!rsIsObject(meshV2));
+
+    rs_allocation meshI0 = rsMeshGetIndexAllocation(mesh, 0);
+    rs_allocation meshI1 = rsMeshGetIndexAllocation(mesh, 1);
+    rs_allocation meshI2 = rsMeshGetIndexAllocation(mesh, 2);
+    rs_allocation meshI3 = rsMeshGetIndexAllocation(mesh, 3);
+    _RS_ASSERT(meshI0.p == indexAlloc0.p);
+    _RS_ASSERT(!rsIsObject(meshI1));
+    _RS_ASSERT(meshI2.p == indexAlloc2.p);
+    _RS_ASSERT(!rsIsObject(meshI3));
+
+    rs_primitive p0 = rsMeshGetPrimitive(mesh, 0);
+    rs_primitive p1 = rsMeshGetPrimitive(mesh, 1);
+    rs_primitive p2 = rsMeshGetPrimitive(mesh, 2);
+    rs_primitive p3 = rsMeshGetPrimitive(mesh, 3);
+
+    _RS_ASSERT(p0 == RS_PRIMITIVE_POINT);
+    _RS_ASSERT(p1 == RS_PRIMITIVE_LINE);
+    _RS_ASSERT(p2 == RS_PRIMITIVE_TRIANGLE);
+    _RS_ASSERT(p3 == RS_PRIMITIVE_INVALID);
+
+    if (failed) {
+        rsDebug("test_mesh_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_mesh_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void mesh_test() {
+    bool failed = false;
+    failed |= test_mesh_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
new file mode 100644
index 0000000..11b8c30
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
@@ -0,0 +1,37 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_raster pointSpriteEnabled;
+rs_program_raster cullMode;
+
+static bool test_program_raster_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
+    _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
+
+    _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false);
+    _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
+
+    if (failed) {
+        rsDebug("test_program_raster_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_program_raster_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void program_raster_test() {
+    bool failed = false;
+    failed |= test_program_raster_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
new file mode 100644
index 0000000..3cd8a20
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
@@ -0,0 +1,128 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_store ditherEnable;
+rs_program_store colorRWriteEnable;
+rs_program_store colorGWriteEnable;
+rs_program_store colorBWriteEnable;
+rs_program_store colorAWriteEnable;
+rs_program_store blendSrc;
+rs_program_store blendDst;
+rs_program_store depthWriteEnable;
+rs_program_store depthFunc;
+
+static bool test_program_store_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
+
+    _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
+    _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false);
+    _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
+    _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
+
+    if (failed) {
+        rsDebug("test_program_store_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_program_store_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void program_store_test() {
+    bool failed = false;
+    failed |= test_program_store_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
new file mode 100644
index 0000000..ac9a549
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
@@ -0,0 +1,63 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+rs_sampler minification;
+rs_sampler magnification;
+rs_sampler wrapS;
+rs_sampler wrapT;
+rs_sampler anisotropy;
+
+static bool test_sampler_getters() {
+    bool failed = false;
+
+    _RS_ASSERT(rsgSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
+    _RS_ASSERT(rsgSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(minification) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
+    _RS_ASSERT(rsgSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(magnification) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
+    _RS_ASSERT(rsgSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(wrapS) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(wrapT) == 1.0f);
+
+    _RS_ASSERT(rsgSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
+    _RS_ASSERT(rsgSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
+    _RS_ASSERT(rsgSamplerGetAnisotropy(anisotropy) == 8.0f);
+
+    if (failed) {
+        rsDebug("test_sampler_getters FAILED", 0);
+    }
+    else {
+        rsDebug("test_sampler_getters PASSED", 0);
+    }
+
+    return failed;
+}
+
+void sampler_test() {
+    bool failed = false;
+    failed |= test_sampler_getters();
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs
new file mode 100644
index 0000000..1cd728e
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs
@@ -0,0 +1,37 @@
+#include "shared.rsh"
+
+typedef struct Point2 {
+   int x;
+   int y;
+} Point_2;
+Point_2 *point2;
+
+static bool test_Point_2(int expected) {
+    bool failed = false;
+
+    rsDebug("Point: ", point2[0].x, point2[0].y);
+    _RS_ASSERT(point2[0].x == expected);
+    _RS_ASSERT(point2[0].y == expected);
+
+    if (failed) {
+        rsDebug("test_Point_2 FAILED", 0);
+    }
+    else {
+        rsDebug("test_Point_2 PASSED", 0);
+    }
+
+    return failed;
+}
+
+void struct_test(int expected) {
+    bool failed = false;
+    failed |= test_Point_2(expected);
+
+    if (failed) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    }
+    else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
+
diff --git a/tests/SerialChat/Android.mk b/tests/SerialChat/Android.mk
new file mode 100644
index 0000000..a534e1a
--- /dev/null
+++ b/tests/SerialChat/Android.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SerialChat
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SerialChat/AndroidManifest.xml b/tests/SerialChat/AndroidManifest.xml
new file mode 100644
index 0000000..0efdb58
--- /dev/null
+++ b/tests/SerialChat/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.serialchat">
+
+    <uses-permission android:name="android.permission.SERIAL_PORT"/>
+
+    <application android:label="Serial Chat">
+        <activity android:name="SerialChat" android:label="Serial Chat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/SerialChat/res/layout/serial_chat.xml b/tests/SerialChat/res/layout/serial_chat.xml
new file mode 100644
index 0000000..596ecbf
--- /dev/null
+++ b/tests/SerialChat/res/layout/serial_chat.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    >
+
+    <ScrollView android:id="@+id/scroll"
+        android:layout_width="match_parent"
+        android:layout_height="0px"
+        android:layout_weight="1"
+        >
+        <TextView android:id="@+id/log"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="25dp"
+            android:textSize="12sp"
+            android:textColor="#ffffffff"
+            />
+    </ScrollView>
+
+    <EditText android:id="@+id/message"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:capitalize="sentences"
+        android:autoText="true"
+        android:singleLine="true"
+        />
+
+</LinearLayout>
+
+
diff --git a/tests/SerialChat/src/com/android/serialchat/SerialChat.java b/tests/SerialChat/src/com/android/serialchat/SerialChat.java
new file mode 100644
index 0000000..faec312
--- /dev/null
+++ b/tests/SerialChat/src/com/android/serialchat/SerialChat.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.serialchat;
+
+import android.app.Activity;
+import android.content.Context;
+import android.hardware.SerialManager;
+import android.hardware.SerialPort;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.util.Log;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.nio.ByteBuffer;
+import java.io.IOException;
+
+public class SerialChat extends Activity implements Runnable, TextView.OnEditorActionListener {
+
+    private static final String TAG = "SerialChat";
+
+    private TextView mLog;
+    private EditText mEditText;
+    private ByteBuffer mInputBuffer;
+    private ByteBuffer mOutputBuffer;
+    private SerialManager mSerialManager;
+    private SerialPort mSerialPort;
+    private boolean mPermissionRequestPending;
+
+    private static final int MESSAGE_LOG = 1;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mSerialManager = (SerialManager)getSystemService(Context.SERIAL_SERVICE);
+        setContentView(R.layout.serial_chat);
+        mLog = (TextView)findViewById(R.id.log);
+        mEditText = (EditText)findViewById(R.id.message);
+        mEditText.setOnEditorActionListener(this);
+
+        if (false) {
+            mInputBuffer = ByteBuffer.allocateDirect(1024);
+            mOutputBuffer = ByteBuffer.allocateDirect(1024);
+        } else {
+            mInputBuffer = ByteBuffer.allocate(1024);
+            mOutputBuffer = ByteBuffer.allocate(1024);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        String[] ports = mSerialManager.getSerialPorts();
+        if (ports != null && ports.length > 0) {
+            try {
+                mSerialPort = mSerialManager.openSerialPort(ports[0], 115200);
+                if (mSerialPort != null) {
+                    new Thread(this).start();
+                }
+            } catch (IOException e) {
+            }
+        }
+
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mSerialPort != null) {
+            try {
+                mSerialPort.close();
+            } catch (IOException e) {
+            }
+            mSerialPort = null;
+        }
+        super.onDestroy();
+    }
+
+    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+        if (/* actionId == EditorInfo.IME_ACTION_DONE && */ mSerialPort != null) {
+            try {
+                String text = v.getText().toString();
+                Log.d(TAG, "write: " + text);
+                byte[] bytes = text.getBytes();
+                mOutputBuffer.clear();
+                mOutputBuffer.put(bytes);
+                mSerialPort.write(mOutputBuffer, bytes.length);
+            } catch (IOException e) {
+                Log.e(TAG, "write failed", e);
+            }
+            v.setText("");
+            return true;
+        }
+        Log.d(TAG, "onEditorAction " + actionId + " event: " + event);
+        return false;
+    }
+
+    public void run() {
+        Log.d(TAG, "run");
+        int ret = 0;
+        byte[] buffer = new byte[1024];
+        while (ret >= 0) {
+            try {
+                Log.d(TAG, "calling read");
+                mInputBuffer.clear();
+                ret = mSerialPort.read(mInputBuffer);
+                Log.d(TAG, "read returned " + ret);
+                mInputBuffer.get(buffer, 0, ret);
+            } catch (IOException e) {
+                Log.e(TAG, "read failed", e);
+                break;
+            }
+
+            if (ret > 0) {
+                Message m = Message.obtain(mHandler, MESSAGE_LOG);
+                String text = new String(buffer, 0, ret);
+                Log.d(TAG, "chat: " + text);
+                m.obj = text;
+                mHandler.sendMessage(m);
+            }
+        }
+        Log.d(TAG, "thread out");
+    }
+
+   Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_LOG:
+                    mLog.setText(mLog.getText() + (String)msg.obj);
+                    break;
+             }
+        }
+    };
+}
+
+
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
index 5f53a9b..1a2dcb9 100644
--- a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
@@ -19,12 +19,21 @@
 import com.android.internal.os.RuntimeInit;
 
 import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
 import android.content.Context;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 /**
  * This smoke test is designed to quickly sniff for any error conditions
@@ -32,53 +41,125 @@
  */
 public class ProcessErrorsTest extends AndroidTestCase {
     
-    private final String TAG = "ProcessErrorsTest";
+    private static final String TAG = "ProcessErrorsTest";
     
     protected ActivityManager mActivityManager;
+    protected PackageManager mPackageManager;
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mActivityManager = (ActivityManager) 
+        mActivityManager = (ActivityManager)
                 getContext().getSystemService(Context.ACTIVITY_SERVICE);
+        mPackageManager = getContext().getPackageManager();
     }
 
     public void testSetUpConditions() throws Exception {
         assertNotNull(mActivityManager);
+        assertNotNull(mPackageManager);
     }
 
     public void testNoProcessErrors() throws Exception {
-        List<ActivityManager.ProcessErrorStateInfo> errList;        
+        final String reportMsg = checkForProcessErrors();
+        if (reportMsg != null) {
+            Log.w(TAG, reportMsg);
+        }
+
+        // report a non-empty list back to the test framework
+        assertNull(reportMsg, reportMsg);
+    }
+
+    private String checkForProcessErrors() throws Exception {
+        List<ProcessErrorStateInfo> errList;
         errList = mActivityManager.getProcessesInErrorState();
         
         // note: this contains information about each process that is currently in an error
         // condition.  if the list is empty (null) then "we're good".  
         
         // if the list is non-empty, then it's useful to report the contents of the list
-        // we'll put a copy in the log, and we'll report it back to the framework via the assert.
         final String reportMsg = reportListContents(errList);
-        if (reportMsg != null) {
-            Log.w(TAG, reportMsg);
-        }
-        
-        // report a non-empty list back to the test framework
-        assertNull(reportMsg, errList);
+        return reportMsg;
     }
-    
+
+    /**
+     * A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes
+     * happened while doing so.
+     * <p />
+     * FIXME: Doesn't detect multiple crashing apps properly, since the crash dialog for the
+     * FIXME: first app doesn't go away.
+     */
+    public void testRunAllActivities() throws Exception {
+        final Intent home = new Intent(Intent.ACTION_MAIN);
+        home.addCategory(Intent.CATEGORY_HOME);
+        home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        final Intent launchable = new Intent(Intent.ACTION_MAIN);
+        launchable.addCategory(Intent.CATEGORY_LAUNCHER);
+        final List<ResolveInfo> activities = mPackageManager.queryIntentActivities(launchable, 0);
+        final Set<ProcessError> errSet = new HashSet<ProcessError>();
+
+        for (ResolveInfo info : activities) {
+            Log.i(TAG, String.format("Got %s/%s", info.activityInfo.packageName,
+                    info.activityInfo.name));
+
+            // build an Intent to launch the app
+            final ComponentName component = new ComponentName(info.activityInfo.packageName,
+                    info.activityInfo.name);
+            final Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.setComponent(component);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            // launch app, and wait 7 seconds for it to start/settle
+            getContext().startActivity(intent);
+            try {
+                Thread.sleep(7000);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+
+            // See if there are any errors
+            Collection<ProcessErrorStateInfo> procs = mActivityManager.getProcessesInErrorState();
+            if (procs != null) {
+                errSet.addAll(ProcessError.fromCollection(procs));
+            }
+
+            // Send the "home" intent and wait 2 seconds for us to get there
+            getContext().startActivity(home);
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+
+        if (!errSet.isEmpty()) {
+            fail(String.format("Got %d errors: %s", errSet.size(),
+                    reportWrappedListContents(errSet)));
+        }
+    }
+
+    private String reportWrappedListContents(Collection<ProcessError> errList) {
+        List<ProcessErrorStateInfo> newList = new ArrayList<ProcessErrorStateInfo>(errList.size());
+        for (ProcessError err : errList) {
+            newList.add(err.info);
+        }
+        return reportListContents(newList);
+    }
+
     /**
      * This helper function will dump the actual error reports.
      * 
      * @param errList The error report containing one or more error records.
      * @return Returns a string containing all of the errors.
      */
-    private String reportListContents(List<ActivityManager.ProcessErrorStateInfo> errList) {
+    private String reportListContents(Collection<ProcessErrorStateInfo> errList) {
         if (errList == null) return null;
 
         StringBuilder builder = new StringBuilder();
 
-        Iterator<ActivityManager.ProcessErrorStateInfo> iter = errList.iterator();
+        Iterator<ProcessErrorStateInfo> iter = errList.iterator();
         while (iter.hasNext()) {
-            ActivityManager.ProcessErrorStateInfo entry = iter.next();
+            ProcessErrorStateInfo entry = iter.next();
 
             String condition;
             switch (entry.condition) {
@@ -96,8 +177,77 @@
             builder.append("Process error ").append(condition).append(" ");
             builder.append(" ").append(entry.shortMsg);
             builder.append(" detected in ").append(entry.processName).append(" ").append(entry.tag);
+            builder.append("\n");
         }
         return builder.toString();
     }
-    
+
+    /**
+     * A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent
+     * crashes are considered equal).
+     */
+    private static class ProcessError {
+        public final ProcessErrorStateInfo info;
+
+        public ProcessError(ProcessErrorStateInfo newInfo) {
+            info = newInfo;
+        }
+
+        public static Collection<ProcessError> fromCollection(Collection<ProcessErrorStateInfo> in)
+                {
+            List<ProcessError> out = new ArrayList<ProcessError>(in.size());
+            for (ProcessErrorStateInfo info : in) {
+                out.add(new ProcessError(info));
+            }
+            return out;
+        }
+
+        private boolean strEquals(String a, String b) {
+            if ((a == null) && (b == null)) {
+                return true;
+            } else if ((a == null) || (b == null)) {
+                return false;
+            } else {
+                return a.equals(b);
+            }
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other == null) return false;
+            if (!(other instanceof ProcessError)) return false;
+            ProcessError peOther = (ProcessError) other;
+
+            return (info.condition == peOther.info.condition)
+                    && strEquals(info.longMsg, peOther.info.longMsg)
+                    && (info.pid == peOther.info.pid)
+                    && strEquals(info.processName, peOther.info.processName)
+                    && strEquals(info.shortMsg, peOther.info.shortMsg)
+                    && strEquals(info.stackTrace, peOther.info.stackTrace)
+                    && strEquals(info.tag, peOther.info.tag)
+                    && (info.uid == peOther.info.uid);
+        }
+
+        private int hash(Object obj) {
+            if (obj == null) {
+                return 13;
+            } else {
+                return obj.hashCode();
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            int code = 17;
+            code += info.condition;
+            code *= hash(info.longMsg);
+            code += info.pid;
+            code *= hash(info.processName);
+            code *= hash(info.shortMsg);
+            code *= hash(info.stackTrace);
+            code *= hash(info.tag);
+            code += info.uid;
+            return code;
+        }
+    }
 }
diff --git a/tests/SmokeTestApps/Android.mk b/tests/SmokeTestApps/Android.mk
new file mode 100644
index 0000000..3f5f011
--- /dev/null
+++ b/tests/SmokeTestApps/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := SmokeTestTriggerApps
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/SmokeTestApps/AndroidManifest.xml b/tests/SmokeTestApps/AndroidManifest.xml
new file mode 100644
index 0000000..0f20107
--- /dev/null
+++ b/tests/SmokeTestApps/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.smoketest.triggers">
+
+    <application android:label="something">
+        <activity android:name=".CrashyApp"
+                  android:label="Test Crashy App">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".CrashyApp2"
+                  android:label="Test Crashy App2">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".UnresponsiveApp"
+                  android:label="Test Unresponsive App">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/SmokeTestApps/README b/tests/SmokeTestApps/README
new file mode 100644
index 0000000..04aa366
--- /dev/null
+++ b/tests/SmokeTestApps/README
@@ -0,0 +1,3 @@
+The apps in this folder are intentionally bad-behaving apps that are intended
+to trigger the smoke tests to fail.  They are otherwise not useful.
+
diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java
new file mode 100644
index 0000000..c11b0f3
--- /dev/null
+++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+package com.android.smoketest.triggers;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class CrashyApp extends Activity {
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        TextView tv = new TextView(this);
+        tv.setText("Hello, Crashy Android");
+        setContentView(tv);
+    }
+
+    @Override
+    public void onResume() {
+        ((String) null).length();
+    }
+}
diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp2.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp2.java
new file mode 100644
index 0000000..3ef5b2b
--- /dev/null
+++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp2.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+package com.android.smoketest.triggers;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class CrashyApp2 extends Activity {
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        TextView tv = new TextView(this);
+        tv.setText("Hello, Other Crashy Android");
+        setContentView(tv);
+    }
+
+
+    @Override
+    public void onResume() {
+        throw new RuntimeException("Two drums and a cymbal fall off a cliff...");
+    }
+}
diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/UnresponsiveApp.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/UnresponsiveApp.java
new file mode 100644
index 0000000..1291897
--- /dev/null
+++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/UnresponsiveApp.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+package com.android.smoketest.triggers;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class UnresponsiveApp extends Activity {
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        TextView tv = new TextView(this);
+        tv.setText("Hello, Unresponsive Android");
+        setContentView(tv);
+    }
+
+    @Override
+    public void onResume() {
+        // Attempt to provoke the ire of the ActivityManager
+        while (true) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                // ignore
+            }
+        }
+    }
+}
diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml
index 5af52dc..6c7055b 100644
--- a/tests/TileBenchmark/res/values/strings.xml
+++ b/tests/TileBenchmark/res/values/strings.xml
@@ -49,8 +49,9 @@
     <!-- Drop down menu entry - automatically scroll to the end of the page
     with scrollBy() [CHAR LIMIT=15] -->
     <string name="movement_auto_scroll">Auto-scroll</string>
-    <!-- Drop down menu entry -  [CHAR LIMIT=15] -->
-    <string name="movement_auto_fling">Auto-fling</string>
+    <!-- Drop down menu entry - automatically record for a set time before
+    stopping [CHAR LIMIT=15] -->
+    <string name="movement_timed">Timed</string>
     <!-- Drop down menu entry - manually navigate the page(s), hit 'capture'
     button [CHAR LIMIT=15] -->
     <string name="movement_manual">Manual</string>
@@ -67,14 +68,21 @@
     <!-- 75th percentile - 75% of frames fall below this value [CHAR LIMIT=12]
     -->
     <string name="percentile_75">75%ile</string>
+    <!-- standard deviation [CHAR LIMIT=12] -->
+    <string name="std_dev">StdDev</string>
+    <!-- mean [CHAR LIMIT=12] -->
+    <string name="mean">mean</string>
+
+
+
     <!-- Frame rate [CHAR LIMIT=15] -->
     <string name="frames_per_second">Frames/sec</string>
     <!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] -->
     <string name="viewport_coverage">Coverage</string>
     <!-- Milliseconds taken to inval, and re-render the page [CHAR LIMIT=15] -->
     <string name="render_millis">RenderMillis</string>
-    <!-- Number of rendering stalls while running the test [CHAR LIMIT=15] -->
-    <string name="render_stalls">Stalls</string>
+    <!-- Animation Framerate [CHAR LIMIT=15] -->
+    <string name="animation_framerate">AnimFramerate</string>
     <!-- Format string for stat value overlay [CHAR LIMIT=15] -->
     <string name="format_stat">%4.4f</string>
 
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
index cc39b75..6356cc1 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
@@ -27,17 +27,57 @@
 import android.os.Environment;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
+import android.webkit.WebSettings;
+import android.widget.Spinner;
 
 public class PerformanceTest extends
         ActivityInstrumentationTestCase2<ProfileActivity> {
 
+    public static class AnimStat {
+        double aggVal = 0;
+        double aggSqrVal = 0;
+        double count = 0;
+    }
+
     private class StatAggregator extends PlaybackGraphs {
         private HashMap<String, Double> mDataMap = new HashMap<String, Double>();
+        private HashMap<String, AnimStat> mAnimDataMap = new HashMap<String, AnimStat>();
         private int mCount = 0;
 
+
         public void aggregate() {
+            boolean inAnimTests = mAnimTests != null;
+            Resources resources = mWeb.getResources();
+            String animFramerateString = resources.getString(R.string.animation_framerate);
+            for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
+                String name = e.getKey();
+                if (inAnimTests) {
+                    if (name.equals(animFramerateString)) {
+                        // in animation testing phase, record animation framerate and aggregate
+                        // stats, differentiating on values of mAnimTestNr and mDoubleBuffering
+                        String fullName = ANIM_TEST_NAMES[mAnimTestNr] + " " + name;
+                        fullName += mDoubleBuffering ? " tiled" : " webkit";
+
+                        if (!mAnimDataMap.containsKey(fullName)) {
+                            mAnimDataMap.put(fullName, new AnimStat());
+                        }
+                        AnimStat statVals = mAnimDataMap.get(fullName);
+                        statVals.aggVal += e.getValue();
+                        statVals.aggSqrVal += e.getValue() * e.getValue();
+                        statVals.count += 1;
+                    }
+                } else {
+                    double aggVal = mDataMap.containsKey(name)
+                            ? mDataMap.get(name) : 0;
+                    mDataMap.put(name, aggVal + e.getValue());
+                }
+            }
+
+            if (inAnimTests) {
+                return;
+            }
+
             mCount++;
-            Resources resources = mView.getResources();
             for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
                 for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
                     String metricLabel = resources.getString(
@@ -53,34 +93,47 @@
                     mDataMap.put(label, aggVal);
                 }
             }
-            for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
-                double aggVal = mDataMap.containsKey(e.getKey())
-                        ? mDataMap.get(e.getKey()) : 0;
-                mDataMap.put(e.getKey(), aggVal + e.getValue());
-            }
+
         }
 
+        // build the final bundle of results
         public Bundle getBundle() {
             Bundle b = new Bundle();
-            int count = 0 == mCount ? Integer.MAX_VALUE : mCount;
+            int count = (0 == mCount) ? Integer.MAX_VALUE : mCount;
             for (Map.Entry<String, Double> e : mDataMap.entrySet()) {
                 b.putDouble(e.getKey(), e.getValue() / count);
             }
+
+            for (Map.Entry<String, AnimStat> e : mAnimDataMap.entrySet()) {
+                String statName = e.getKey();
+                AnimStat statVals = e.getValue();
+
+                double avg = statVals.aggVal/statVals.count;
+                double stdDev = Math.sqrt((statVals.aggSqrVal / statVals.count) - avg * avg);
+
+                b.putDouble(statName, avg);
+                b.putDouble(statName + " STD DEV", stdDev);
+            }
+
             return b;
         }
     }
 
     ProfileActivity mActivity;
-    ProfiledWebView mView;
-    StatAggregator mStats = new StatAggregator();
+    ProfiledWebView mWeb;
+    Spinner mMovementSpinner;
+    StatAggregator mStats;
 
     private static final String LOGTAG = "PerformanceTest";
     private static final String TEST_LOCATION = "webkit/page_cycler";
     private static final String URL_PREFIX = "file://";
     private static final String URL_POSTFIX = "/index.html?skip=true";
     private static final int MAX_ITERATIONS = 4;
-    private static final String TEST_DIRS[] = {
-        "alexa25_2011"//, "alexa_us", "android", "dom", "intl2", "moz", "moz2"
+    private static final String SCROLL_TEST_DIRS[] = {
+        "alexa25_2011"
+    };
+    private static final String ANIM_TEST_DIRS[] = {
+        "dhtml"
     };
 
     public PerformanceTest() {
@@ -91,7 +144,22 @@
     protected void setUp() throws Exception {
         super.setUp();
         mActivity = getActivity();
-        mView = (ProfiledWebView) mActivity.findViewById(R.id.web);
+        mWeb = (ProfiledWebView) mActivity.findViewById(R.id.web);
+        mMovementSpinner = (Spinner) mActivity.findViewById(R.id.movement);
+        mStats = new StatAggregator();
+
+        // use mStats as a condition variable between the UI thread and
+        // this(the testing) thread
+        mActivity.setCallback(new ProfileCallback() {
+            @Override
+            public void profileCallback(RunData data) {
+                mStats.setData(data);
+                synchronized (mStats) {
+                    mStats.notify();
+                }
+            }
+        });
+
     }
 
     private boolean loadUrl(final String url) {
@@ -100,12 +168,13 @@
             mActivity.runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
-                    mView.loadUrl(url);
+                    mWeb.loadUrl(url);
                 }
             });
             synchronized (mStats) {
                 mStats.wait();
             }
+
             mStats.aggregate();
         } catch (InterruptedException e) {
             e.printStackTrace();
@@ -114,15 +183,30 @@
         return true;
     }
 
-    private boolean runIteration() {
+    private boolean validTest(String nextTest) {
+        // if testing animations, test must be in mAnimTests
+        if (mAnimTests == null)
+            return true;
+
+        for (String test : mAnimTests) {
+            if (test.equals(nextTest)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean runIteration(String[] testDirs) {
         File sdFile = Environment.getExternalStorageDirectory();
-        for (String testDirName : TEST_DIRS) {
+        for (String testDirName : testDirs) {
             File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName);
             Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath()
                     + "', exists=" + testDir.exists());
+
             for (File siteDir : testDir.listFiles()) {
-                if (!siteDir.isDirectory())
+                if (!siteDir.isDirectory() || !validTest(siteDir.getName())) {
                     continue;
+                }
 
                 if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath()
                         + URL_POSTFIX)) {
@@ -133,7 +217,44 @@
         return true;
     }
 
-    public void testMetrics() {
+    private boolean  runTestDirs(String[] testDirs) {
+        for (int i = 0; i < MAX_ITERATIONS; i++)
+            if (!runIteration(testDirs)) {
+                return false;
+            }
+        return true;
+    }
+
+    private void pushDoubleBuffering() {
+        getInstrumentation().runOnMainSync(new Runnable() {
+            public void run() {
+                mWeb.setDoubleBuffering(mDoubleBuffering);
+            }
+        });
+    }
+
+    private void setScrollingTestingMode(final boolean scrolled) {
+        getInstrumentation().runOnMainSync(new Runnable() {
+            public void run() {
+                mMovementSpinner.setSelection(scrolled ? 0 : 2);
+            }
+        });
+    }
+
+
+    private String[] mAnimTests = null;
+    private int mAnimTestNr = -1;
+    private boolean mDoubleBuffering = true;
+    private static final String[] ANIM_TEST_NAMES = {
+        "slow", "fast"
+    };
+    private static final String[][] ANIM_TESTS = {
+        {"scrolling", "replaceimages", "layers5", "layers1"},
+        {"slidingballs", "meter", "slidein", "fadespacing", "colorfade",
+                "mozilla", "movingtext", "diagball", "zoom", "imageslide"},
+    };
+
+    private boolean checkMedia() {
         String state = Environment.getExternalStorageState();
 
         if (!Environment.MEDIA_MOUNTED.equals(state)
@@ -141,27 +262,43 @@
             Log.d(LOGTAG, "ARG Can't access sd card!");
             // Can't read the SD card, fail and die!
             getInstrumentation().sendStatus(1, null);
-            return;
+            return false;
         }
+        return true;
+    }
 
-        // use mGraphs as a condition variable between the UI thread and
-        // this(the testing) thread
-        mActivity.setCallback(new ProfileCallback() {
-            @Override
-            public void profileCallback(RunData data) {
-                Log.d(LOGTAG, "test completion callback");
-                mStats.setData(data);
-                synchronized (mStats) {
-                    mStats.notify();
+    public void testMetrics() {
+        setScrollingTestingMode(true);
+        if (checkMedia() && runTestDirs(SCROLL_TEST_DIRS)) {
+            getInstrumentation().sendStatus(0, mStats.getBundle());
+        } else {
+            getInstrumentation().sendStatus(1, null);
+        }
+    }
+
+    private boolean runAnimationTests() {
+        for (int doubleBuffer = 0; doubleBuffer <= 1; doubleBuffer++) {
+            mDoubleBuffering = doubleBuffer == 1;
+            pushDoubleBuffering();
+            for (mAnimTestNr = 0; mAnimTestNr < ANIM_TESTS.length; mAnimTestNr++) {
+                mAnimTests = ANIM_TESTS[mAnimTestNr];
+                if (!runTestDirs(ANIM_TEST_DIRS)) {
+                    return false;
                 }
             }
-        });
+        }
+        return true;
+    }
 
-        for (int i = 0; i < MAX_ITERATIONS; i++)
-            if (!runIteration()) {
-                getInstrumentation().sendStatus(1, null);
-                return;
-            }
-        getInstrumentation().sendStatus(0, mStats.getBundle());
+    public void testAnimations() {
+        // instead of autoscrolling, load each page until either an timer fires,
+        // or the animation signals complete via javascript
+        setScrollingTestingMode(false);
+
+        if (checkMedia() && runAnimationTests()) {
+            getInstrumentation().sendStatus(0, mStats.getBundle());
+        } else {
+            getInstrumentation().sendStatus(1, null);
+        }
     }
 }
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
index 9ea90f8..a3ae9be 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
@@ -80,7 +80,7 @@
                     for (int tileID = 1; tileID < frame.length; tileID++) {
                         TileData data = frame[tileID];
                         double coverage = viewportCoverage(frame[0], data);
-                        total += coverage * (data.isReady ? 1 : 0);
+                        total += coverage * (data.isReady ? 100 : 0);
                         totalCount += coverage;
                     }
                     if (totalCount == 0) {
@@ -91,7 +91,7 @@
 
                 @Override
                 public double getMax() {
-                    return 1;
+                    return 100;
                 }
 
                 @Override
@@ -108,6 +108,9 @@
     }
 
     public static double getPercentile(double sortedValues[], double ratioAbove) {
+        if (sortedValues.length == 0)
+            return -1;
+
         double index = ratioAbove * (sortedValues.length - 1);
         int intIndex = (int) Math.floor(index);
         if (index == intIndex) {
@@ -118,6 +121,31 @@
                 + sortedValues[intIndex + 1] * (alpha);
     }
 
+    public static double getMean(double sortedValues[]) {
+        if (sortedValues.length == 0)
+            return -1;
+
+        double agg = 0;
+        for (double val : sortedValues) {
+            agg += val;
+        }
+        return agg / sortedValues.length;
+    }
+
+    public static double getStdDev(double sortedValues[]) {
+        if (sortedValues.length == 0)
+            return -1;
+
+        double agg = 0;
+        double sqrAgg = 0;
+        for (double val : sortedValues) {
+            agg += val;
+            sqrAgg += val*val;
+        }
+        double mean = agg / sortedValues.length;
+        return Math.sqrt((sqrAgg / sortedValues.length) - (mean * mean));
+    }
+
     protected static StatGen[] Stats = new StatGen[] {
             new StatGen() {
                 @Override
@@ -149,6 +177,26 @@
                 public int getLabelId() {
                     return R.string.percentile_75;
                 }
+            }, new StatGen() {
+                @Override
+                public double getValue(double[] sortedValues) {
+                    return getStdDev(sortedValues);
+                }
+
+                @Override
+                public int getLabelId() {
+                    return R.string.std_dev;
+                }
+            }, new StatGen() {
+                @Override
+                public double getValue(double[] sortedValues) {
+                    return getMean(sortedValues);
+                }
+
+                @Override
+                public int getLabelId() {
+                    return R.string.mean;
+                }
             },
     };
 
@@ -159,40 +207,47 @@
     }
 
     private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
-    protected double[][] mStats = new double[Metrics.length][Stats.length];
+    protected final double[][] mStats = new double[Metrics.length][Stats.length];
     protected HashMap<String, Double> mSingleStats;
 
+    private void gatherFrameMetric(int metricIndex, double metricValues[], RunData data) {
+        // create graph out of rectangles, one per frame
+        int lastBar = 0;
+        for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
+            TileData frame[] = data.frames[frameIndex];
+            int newBar = (frame[0].top + frame[0].bottom) / 2;
+
+            MetricGen s = Metrics[metricIndex];
+            double absoluteValue = s.getValue(frame);
+            double relativeValue = absoluteValue / s.getMax();
+            relativeValue = Math.min(1,relativeValue);
+            relativeValue = Math.max(0,relativeValue);
+            int rightPos = (int) (-BAR_WIDTH * metricIndex);
+            int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
+
+            ShapeDrawable graphBar = new ShapeDrawable();
+            graphBar.getPaint().setColor(Color.BLUE);
+            graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
+
+            mShapes.add(graphBar);
+            metricValues[frameIndex] = absoluteValue;
+            lastBar = newBar;
+        }
+    }
+
     public void setData(RunData data) {
         mShapes.clear();
         double metricValues[] = new double[data.frames.length];
 
+        mSingleStats = data.singleStats;
+
         if (data.frames.length == 0) {
             return;
         }
 
         for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
-            // create graph out of rectangles, one per frame
-            int lastBar = 0;
-            for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
-                TileData frame[] = data.frames[frameIndex];
-                int newBar = (frame[0].top + frame[0].bottom) / 2;
-
-                MetricGen s = Metrics[metricIndex];
-                double absoluteValue = s.getValue(frame);
-                double relativeValue = absoluteValue / s.getMax();
-                relativeValue = Math.min(1,relativeValue);
-                relativeValue = Math.max(0,relativeValue);
-                int rightPos = (int) (-BAR_WIDTH * metricIndex);
-                int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
-
-                ShapeDrawable graphBar = new ShapeDrawable();
-                graphBar.getPaint().setColor(Color.BLUE);
-                graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
-
-                mShapes.add(graphBar);
-                metricValues[frameIndex] = absoluteValue;
-                lastBar = newBar;
-            }
+            // calculate metric based on list of frames
+            gatherFrameMetric(metricIndex, metricValues, data);
 
             // store aggregate statistics per metric (median, and similar)
             Arrays.sort(metricValues);
@@ -200,8 +255,6 @@
                 mStats[metricIndex][statIndex] =
                         Stats[statIndex].getValue(metricValues);
             }
-
-            mSingleStats = data.singleStats;
         }
     }
 
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
index d38d006..2e77157 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
@@ -22,11 +22,12 @@
 import android.graphics.Bitmap;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.util.Log;
 import android.util.Pair;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.AdapterView;
@@ -49,6 +50,8 @@
  */
 public class ProfileActivity extends Activity {
 
+    private static final int TIMED_RECORD_MILLIS = 2000;
+
     public interface ProfileCallback {
         public void profileCallback(RunData data);
     }
@@ -65,6 +68,7 @@
 
     LoggingWebViewClient mLoggingWebViewClient = new LoggingWebViewClient();
     AutoLoggingWebViewClient mAutoLoggingWebViewClient = new AutoLoggingWebViewClient();
+    TimedLoggingWebViewClient mTimedLoggingWebViewClient = new TimedLoggingWebViewClient();
 
     private enum TestingState {
         NOT_TESTING,
@@ -93,18 +97,18 @@
         public void onItemSelected(AdapterView<?> parent, View view,
                 int position, long id) {
             String movementStr = parent.getItemAtPosition(position).toString();
-            if (movementStr == getResources().getString(
-                    R.string.movement_auto_scroll)
-                    || movementStr == getResources().getString(
-                            R.string.movement_auto_fling)) {
+            if (movementStr == getResources().getString(R.string.movement_auto_scroll)) {
                 mWeb.setWebViewClient(mAutoLoggingWebViewClient);
                 mCaptureButton.setEnabled(false);
                 mVelocitySpinner.setEnabled(true);
-            } else if (movementStr == getResources().getString(
-                    R.string.movement_manual)) {
+            } else if (movementStr == getResources().getString(R.string.movement_manual)) {
                 mWeb.setWebViewClient(mLoggingWebViewClient);
                 mCaptureButton.setEnabled(true);
                 mVelocitySpinner.setEnabled(false);
+            } else if (movementStr == getResources().getString(R.string.movement_timed)) {
+                mWeb.setWebViewClient(mTimedLoggingWebViewClient);
+                mCaptureButton.setEnabled(false);
+                mVelocitySpinner.setEnabled(false);
             }
         }
 
@@ -124,15 +128,19 @@
             super.onPageStarted(view, url, favicon);
             mUrl.setText(url);
         }
-    }
-
-    private class AutoLoggingWebViewClient extends LoggingWebViewClient {
 
         @Override
         public void onPageFinished(WebView view, String url) {
             super.onPageFinished(view, url);
             view.requestFocus();
+            ((ProfiledWebView)view).onPageFinished();
+        }
+    }
 
+    private class AutoLoggingWebViewClient extends LoggingWebViewClient {
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
             startViewProfiling(true);
         }
 
@@ -143,6 +151,32 @@
         }
     }
 
+    private class TimedLoggingWebViewClient extends LoggingWebViewClient {
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
+            startViewProfiling(false);
+
+            // after a fixed time after page finished, stop testing
+            new CountDownTimer(TIMED_RECORD_MILLIS, TIMED_RECORD_MILLIS) {
+                @Override
+                public void onTick(long millisUntilFinished) {
+                }
+
+                @Override
+                public void onFinish() {
+                    mWeb.stopScrollTest();
+                }
+            }.start();
+        }
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            super.onPageStarted(view, url, favicon);
+            setTestingState(TestingState.PRE_TESTING);
+        }
+    }
+
     private class StoreFileTask extends
             AsyncTask<Pair<String, RunData>, Void, Void> {
 
@@ -178,11 +212,13 @@
                 mMovementSpinner.setEnabled(false);
                 break;
             case START_TESTING:
+                mCaptureButton.setChecked(true);
                 mUrl.setBackgroundResource(R.color.background_start_testing);
                 mInspectButton.setEnabled(false);
                 mMovementSpinner.setEnabled(false);
                 break;
             case STOP_TESTING:
+                mCaptureButton.setChecked(false);
                 mUrl.setBackgroundResource(R.color.background_stop_testing);
                 break;
             case SAVED_TESTING:
@@ -195,7 +231,6 @@
     /** auto - automatically scroll. */
     private void startViewProfiling(boolean auto) {
         // toggle capture button to indicate capture state to user
-        mCaptureButton.setChecked(true);
         mWeb.startScrollTest(mCallback, auto);
         setTestingState(TestingState.START_TESTING);
     }
@@ -217,7 +252,7 @@
             public void profileCallback(RunData data) {
                 new StoreFileTask().execute(new Pair<String, RunData>(
                         TEMP_FILENAME, data));
-                mCaptureButton.setChecked(false);
+                Log.d("ProfileActivity", "stored " + data.frames.length + " frames in file");
                 setTestingState(TestingState.STOP_TESTING);
             }
         });
@@ -245,8 +280,8 @@
         // Movement spinner
         String content[] = {
                 getResources().getString(R.string.movement_auto_scroll),
-                getResources().getString(R.string.movement_auto_fling),
-                getResources().getString(R.string.movement_manual)
+                getResources().getString(R.string.movement_manual),
+                getResources().getString(R.string.movement_timed)
         };
         adapter = new ArrayAdapter<CharSequence>(this,
                 android.R.layout.simple_spinner_item, content);
@@ -270,13 +305,7 @@
         });
 
         // Custom profiling WebView
-        WebSettings settings = mWeb.getSettings();
-        settings.setJavaScriptEnabled(true);
-        settings.setSupportZoom(true);
-        settings.setEnableSmoothTransition(true);
-        settings.setBuiltInZoomControls(true);
-        settings.setLoadWithOverviewMode(true);
-        settings.setProperty("use_minimal_memory", "false"); // prefetch tiles, as browser does
+        mWeb.init(this);
         mWeb.setWebViewClient(new LoggingWebViewClient());
 
         // URL text entry
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
index 83f1668..a38ac251 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
@@ -20,22 +20,32 @@
 import android.os.CountDownTimer;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.webkit.WebSettings;
 import android.webkit.WebView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
 
 import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
 import com.test.tilebenchmark.RunData.TileData;
 
 public class ProfiledWebView extends WebView {
+    private static final String LOGTAG = "ProfiledWebView";
+
     private int mSpeed;
 
     private boolean mIsTesting = false;
     private boolean mIsScrolling = false;
     private ProfileCallback mCallback;
     private long mContentInvalMillis;
-    private boolean mHadToBeForced = false;
     private static final int LOAD_STALL_MILLIS = 2000; // nr of millis after load,
                                                        // before test is forced
 
+    // ignore anim end events until this many millis after load
+    private static final long ANIM_SAFETY_THRESHOLD = 200;
+    private long mLoadTime;
+    private long mAnimationTime;
+
     public ProfiledWebView(Context context) {
         super(context);
     }
@@ -53,6 +63,39 @@
         super(context, attrs, defStyle, privateBrowsing);
     }
 
+    private class JavaScriptInterface {
+        Context mContext;
+
+        /** Instantiate the interface and set the context */
+        JavaScriptInterface(Context c) {
+            mContext = c;
+        }
+
+        /** Show a toast from the web page */
+        public void animationComplete() {
+            Toast.makeText(mContext, "Animation complete!", Toast.LENGTH_SHORT).show();
+            //Log.d(LOGTAG, "anim complete");
+            mAnimationTime = System.currentTimeMillis();
+        }
+    }
+
+    public void init(Context c) {
+        WebSettings settings = getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setSupportZoom(true);
+        settings.setEnableSmoothTransition(true);
+        settings.setBuiltInZoomControls(true);
+        settings.setLoadWithOverviewMode(true);
+        settings.setProperty("use_minimal_memory", "false"); // prefetch tiles, as browser does
+        addJavascriptInterface(new JavaScriptInterface(c), "Android");
+        mAnimationTime = 0;
+        mLoadTime = 0;
+    }
+
+    public void onPageFinished() {
+        mLoadTime = System.currentTimeMillis();
+    }
+
     @Override
     protected void onDraw(android.graphics.Canvas canvas) {
         if (mIsTesting && mIsScrolling) {
@@ -72,9 +115,12 @@
      * scrolling, invalidate all content and redraw it, measuring time taken.
      */
     public void startScrollTest(ProfileCallback callback, boolean autoScrolling) {
-        mIsScrolling = autoScrolling;
         mCallback = callback;
         mIsTesting = false;
+        mIsScrolling = false;
+        WebSettings settings = getSettings();
+        settings.setProperty("tree_updates", "0");
+
 
         if (autoScrolling) {
             // after a while, force it to start even if the pages haven't swapped
@@ -86,13 +132,17 @@
                 @Override
                 public void onFinish() {
                     // invalidate all content, and kick off redraw
-                    registerPageSwapCallback();
+                    Log.d("ProfiledWebView",
+                            "kicking off test with callback registration, and tile discard...");
                     discardAllTextures();
                     invalidate();
-
+                    mIsScrolling = true;
                     mContentInvalMillis = System.currentTimeMillis();
                 }
             }.start();
+        } else {
+            mIsTesting = true;
+            tileProfilingStart();
         }
     }
 
@@ -102,13 +152,36 @@
      */
     @Override
     protected void pageSwapCallback(boolean startAnim) {
-        mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
         super.pageSwapCallback(startAnim);
-        Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis
-                + "millis");
-        mIsTesting = true;
-        invalidate(); // ensure a redraw so that auto-scrolling can occur
-        tileProfilingStart();
+
+        if (!mIsTesting && mIsScrolling) {
+            // kick off testing
+            mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
+            Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis + "millis");
+            mIsTesting = true;
+            invalidate(); // ensure a redraw so that auto-scrolling can occur
+            tileProfilingStart();
+        }
+    }
+
+    private double animFramerate() {
+        WebSettings settings = getSettings();
+        String updatesString = settings.getProperty("tree_updates");
+        int updates = (updatesString == null) ? -1 : Integer.parseInt(updatesString);
+
+        long animationTime;
+        if (mAnimationTime == 0 || mAnimationTime - mLoadTime < ANIM_SAFETY_THRESHOLD) {
+            animationTime = System.currentTimeMillis() - mLoadTime;
+        } else {
+            animationTime = mAnimationTime - mLoadTime;
+        }
+
+        return updates * 1000.0 / animationTime;
+    }
+
+    public void setDoubleBuffering(boolean useDoubleBuffering) {
+        WebSettings settings = getSettings();
+        settings.setProperty("use_double_buffering", useDoubleBuffering ? "true" : "false");
     }
 
     /*
@@ -127,11 +200,12 @@
         // record the time spent (before scrolling) rendering the page
         data.singleStats.put(getResources().getString(R.string.render_millis),
                 (double)mContentInvalMillis);
-        // record if the page render timed out
-        Log.d("ProfiledWebView", "hadtobeforced = " + mHadToBeForced);
-        data.singleStats.put(getResources().getString(R.string.render_stalls),
-                             mHadToBeForced ? 1.0 : 0.0);
-        mHadToBeForced = false;
+
+        // record framerate
+        double framerate = animFramerate();
+        Log.d(LOGTAG, "anim framerate was "+framerate);
+        data.singleStats.put(getResources().getString(R.string.animation_framerate),
+                framerate);
 
         for (int frame = 0; frame < data.frames.length; frame++) {
             data.frames[frame] = new TileData[
@@ -159,6 +233,8 @@
 
     @Override
     public void loadUrl(String url) {
+        mAnimationTime = 0;
+        mLoadTime = 0;
         if (!url.startsWith("http://") && !url.startsWith("file://")) {
             url = "http://" + url;
         }
diff --git a/tests/touchlag/Android.mk b/tests/touchlag/Android.mk
new file mode 100644
index 0000000..4f8aa1e
--- /dev/null
+++ b/tests/touchlag/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	touchlag.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils libutils \
+
+LOCAL_MODULE:= test-touchlag
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_EXECUTABLE)
diff --git a/tests/touchlag/touchlag.cpp b/tests/touchlag/touchlag.cpp
new file mode 100644
index 0000000..df4befb
--- /dev/null
+++ b/tests/touchlag/touchlag.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+#include <linux/input.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <cutils/memory.h>
+#include <asm-generic/mman.h>
+#include <sys/mman.h>
+#include <utils/threads.h>
+#include <unistd.h>
+#include <math.h>
+
+using namespace android;
+
+#ifndef FBIO_WAITFORVSYNC
+#define FBIO_WAITFORVSYNC   _IOW('F', 0x20, __u32)
+#endif
+
+struct Buffer {
+    size_t w;
+    size_t h;
+    size_t s;
+    union {
+        void* addr;
+        uint32_t* pixels;
+    };
+};
+
+void clearBuffer(Buffer* buf, uint32_t pixel) {
+    android_memset32(buf->pixels, pixel, buf->s * buf->h * 4);
+}
+
+void drawTwoPixels(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
+    if (y>0 && y<ssize_t(buf->h)) {
+        uint32_t* bits = buf->pixels + y * buf->s;
+        if (x>=0 && x<buf->w) {
+            bits[x] = pixel;
+        }
+        ssize_t W(w);
+        if ((x+W)>=0 && (x+W)<buf->w) {
+            bits[x+W] = pixel;
+        }
+    }
+}
+
+void drawHLine(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
+    if (y>0 && y<ssize_t(buf->h)) {
+        ssize_t W(w);
+        if (x<0) {
+            W += x;
+            x = 0;
+        }
+        if (x+w > buf->w) {
+            W = buf->w - x;
+        }
+        if (W>0) {
+            uint32_t* bits = buf->pixels + y * buf->s + x;
+            android_memset32(bits, pixel, W*4);
+        }
+    }
+}
+
+void drawRect(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w, size_t h) {
+    ssize_t W(w), H(h);
+    if (x<0) {
+        w += x;
+        x = 0;
+    }
+    if (y<0) {
+        h += y;
+        y = 0;
+    }
+    if (x+w > buf->w)   W = buf->w - x;
+    if (y+h > buf->h)   H = buf->h - y;
+    if (W>0 && H>0) {
+        uint32_t* bits = buf->pixels + y * buf->s + x;
+        for (ssize_t i=0 ; i<H ; i++) {
+            android_memset32(bits, pixel, W*4);
+            bits += buf->s;
+        }
+    }
+}
+
+void drawCircle(Buffer* buf, uint32_t pixel,
+        size_t x0, size_t y0, size_t radius, bool filled = false) {
+    ssize_t f = 1 - radius;
+    ssize_t ddF_x = 1;
+    ssize_t ddF_y = -2 * radius;
+    ssize_t x = 0;
+    ssize_t y = radius;
+    if (filled) {
+        drawHLine(buf, pixel, x0-radius, y0, 2*radius);
+    } else {
+        drawTwoPixels(buf, pixel, x0-radius, y0, 2*radius);
+    }
+    while (x < y) {
+        if (f >= 0) {
+            y--;
+            ddF_y += 2;
+            f += ddF_y;
+        }
+        x++;
+        ddF_x += 2;
+        f += ddF_x;
+        if (filled) {
+            drawHLine(buf, pixel, x0-x, y0+y, 2*x);
+            drawHLine(buf, pixel, x0-x, y0-y, 2*x);
+            drawHLine(buf, pixel, x0-y, y0+x, 2*y);
+            drawHLine(buf, pixel, x0-y, y0-x, 2*y);
+        } else {
+            drawTwoPixels(buf, pixel, x0-x, y0+y, 2*x);
+            drawTwoPixels(buf, pixel, x0-x, y0-y, 2*x);
+            drawTwoPixels(buf, pixel, x0-y, y0+x, 2*y);
+            drawTwoPixels(buf, pixel, x0-y, y0-x, 2*y);
+        }
+    }
+}
+
+class TouchEvents {
+    class EventThread : public Thread {
+        int fd;
+
+        virtual bool threadLoop() {
+            input_event event;
+            int first_down = 0;
+            do {
+                read(fd, &event, sizeof(event));
+                if (event.type == EV_ABS) {
+                    if (event.code == ABS_MT_TRACKING_ID) {
+                        down = event.value == -1 ? 0 : 1;
+                        first_down = down;
+                    }
+                    if (event.code == ABS_MT_POSITION_X) {
+                        x = event.value;
+                    }
+                    if (event.code == ABS_MT_POSITION_Y) {
+                        y = event.value;
+                    }
+                }
+            } while (event.type == EV_SYN);
+            return true;
+        }
+
+    public:
+        int x, y, down;
+        EventThread() : Thread(false),
+                x(0), y(0), down(0)
+        {
+            fd = open("/dev/input/event1", O_RDONLY);
+        }
+};
+    sp<EventThread> thread;
+
+public:
+    TouchEvents() {
+        thread = new EventThread();
+        thread->run("EventThread", PRIORITY_URGENT_DISPLAY);
+    }
+
+    int getMostRecentPosition(int* x, int* y) {
+        *x = thread->x;
+        *y = thread->y;
+        return thread->down;
+    }
+};
+
+
+struct Queue {
+    struct position {
+        int x, y;
+    };
+    int index;
+    position q[16];
+    Queue() : index(0) { }
+    void push(int x, int y) {
+        index++;
+        index &= 0xF;
+        q[index].x = x;
+        q[index].y = y;
+    }
+    void get(int lag, int* x, int* y) {
+        const int i = (index - lag) & 0xF;
+        *x = q[i].x;
+        *y = q[i].y;
+    }
+};
+
+extern char *optarg;
+extern int optind;
+extern int optopt;
+extern int opterr;
+extern int optreset;
+
+void usage(const char* name) {
+    printf("\nusage: %s [-h] [-l lag]\n", name);
+}
+
+int main(int argc, char** argv) {
+    fb_var_screeninfo vi;
+    fb_fix_screeninfo fi;
+
+    int lag = 0;
+    int fd = open("/dev/graphics/fb0", O_RDWR);
+    ioctl(fd, FBIOGET_VSCREENINFO, &vi);
+    ioctl(fd, FBIOGET_FSCREENINFO, &fi);
+    void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    Buffer framebuffer;
+    framebuffer.w = vi.xres;
+    framebuffer.h = vi.yres;
+    framebuffer.s = fi.line_length / (vi.bits_per_pixel >> 3);
+    framebuffer.addr = bits;
+
+    int ch;
+    while ((ch = getopt(argc, argv, "hl:")) != -1) {
+        switch (ch) {
+            case 'l':
+                lag = atoi(optarg);
+                break;
+            case 'h':
+            default:
+                usage(argv[0]);
+                exit(0);
+        }
+    }
+    argc -= optind;
+    argv += optind;
+
+
+    TouchEvents touch;
+    Queue queue;
+
+
+    int x=0, y=0, down=0;
+    int lag_x=0, lag_y=0;
+
+    clearBuffer(&framebuffer, 0);
+    while (true) {
+        uint32_t crt = 0;
+        int err = ioctl(fd, FBIO_WAITFORVSYNC, &crt);
+
+        // draw beam marker
+        drawRect(&framebuffer, 0x400000, framebuffer.w-2, 0, 2, framebuffer.h);
+        // erase screen
+        if (lag) {
+            drawCircle(&framebuffer, 0, lag_x, lag_y, 100);
+            drawHLine(&framebuffer, 0, 0, lag_y, 32);
+        }
+        drawCircle(&framebuffer, 0, x, y, 100, true);
+        drawHLine(&framebuffer, 0, 0, y, 32);
+
+        // draw a line at y=1000
+        drawHLine(&framebuffer, 0x808080, 0, 1000, framebuffer.w);
+
+        // get touch events
+        touch.getMostRecentPosition(&x, &y);
+        queue.push(x, y);
+        queue.get(lag, &lag_x, &lag_y);
+
+        if (lag) {
+            drawCircle(&framebuffer, 0x00FF00, lag_x, lag_y, 100);
+            drawHLine(&framebuffer, 0x00FF00, 0, lag_y, 32);
+        }
+
+        drawCircle(&framebuffer, 0xFFFFFF, x, y, 100, true);
+        drawHLine(&framebuffer, 0xFFFFFF, 0, y, 32);
+
+        // draw end of frame beam marker
+        drawRect(&framebuffer, 0x004000, framebuffer.w-2, 0, 2, framebuffer.h);
+    }
+
+    close(fd);
+    return 0;
+}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index f0c215e..ec61403 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1084,12 +1084,17 @@
         if (out) out->density = ResTable_config::DENSITY_HIGH;
         return true;
     }
-    
+
     if (strcmp(name, "xhdpi") == 0) {
-        if (out) out->density = ResTable_config::DENSITY_MEDIUM*2;
+        if (out) out->density = ResTable_config::DENSITY_XHIGH;
         return true;
     }
-    
+
+    if (strcmp(name, "xxhdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_XXHIGH;
+        return true;
+    }
+
     char* c = (char*)name;
     while (*c >= '0' && *c <= '9') {
         c++;
@@ -1832,6 +1837,49 @@
 // =========================================================================
 // =========================================================================
 
+status_t AaptSymbols::applyJavaSymbols(const sp<AaptSymbols>& javaSymbols)
+{
+    status_t err = NO_ERROR;
+    size_t N = javaSymbols->mSymbols.size();
+    for (size_t i=0; i<N; i++) {
+        const String8& name = javaSymbols->mSymbols.keyAt(i);
+        const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i);
+        ssize_t pos = mSymbols.indexOfKey(name);
+        if (pos < 0) {
+            entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string());
+            err = UNKNOWN_ERROR;
+            continue;
+        }
+        //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
+        //        i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
+        mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol;
+    }
+
+    N = javaSymbols->mNestedSymbols.size();
+    for (size_t i=0; i<N; i++) {
+        const String8& name = javaSymbols->mNestedSymbols.keyAt(i);
+        const sp<AaptSymbols>& symbols = javaSymbols->mNestedSymbols.valueAt(i);
+        ssize_t pos = mNestedSymbols.indexOfKey(name);
+        if (pos < 0) {
+            SourcePos pos;
+            pos.error("Java symbol dir %s not defined\n", name.string());
+            err = UNKNOWN_ERROR;
+            continue;
+        }
+        //printf("**** applying java symbols in dir %s\n", name.string());
+        status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols);
+        if (myerr != NO_ERROR) {
+            err = myerr;
+        }
+    }
+
+    return err;
+}
+
+// =========================================================================
+// =========================================================================
+// =========================================================================
+
 AaptAssets::AaptAssets()
     : AaptDir(String8(), String8()),
       mChanged(false), mHaveIncludedAssets(false), mRes(NULL)
@@ -2399,6 +2447,48 @@
     return sym;
 }
 
+sp<AaptSymbols> AaptAssets::getJavaSymbolsFor(const String8& name)
+{
+    sp<AaptSymbols> sym = mJavaSymbols.valueFor(name);
+    if (sym == NULL) {
+        sym = new AaptSymbols();
+        mJavaSymbols.add(name, sym);
+    }
+    return sym;
+}
+
+status_t AaptAssets::applyJavaSymbols()
+{
+    size_t N = mJavaSymbols.size();
+    for (size_t i=0; i<N; i++) {
+        const String8& name = mJavaSymbols.keyAt(i);
+        const sp<AaptSymbols>& symbols = mJavaSymbols.valueAt(i);
+        ssize_t pos = mSymbols.indexOfKey(name);
+        if (pos < 0) {
+            SourcePos pos;
+            pos.error("Java symbol dir %s not defined\n", name.string());
+            return UNKNOWN_ERROR;
+        }
+        //printf("**** applying java symbols in dir %s\n", name.string());
+        status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const {
+    //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
+    //        sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
+    //        sym.isJavaSymbol ? 1 : 0);
+    if (!mHavePrivateSymbols) return true;
+    if (sym.isPublic) return true;
+    if (includePrivate && sym.isJavaSymbol) return true;
+    return false;
+}
+
 status_t AaptAssets::buildIncludedResources(Bundle* bundle)
 {
     if (!mHaveIncludedAssets) {
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index d5345b2..1c653e1 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -53,17 +53,6 @@
     AXIS_END = AXIS_VERSION,
 };
 
-enum {
-    SDK_CUPCAKE = 3,
-    SDK_DONUT = 4,
-    SDK_ECLAIR = 5,
-    SDK_ECLAIR_0_1 = 6,
-    SDK_MR1 = 7,
-    SDK_FROYO = 8,
-    SDK_HONEYCOMB_MR2 = 13,
-    SDK_ICE_CREAM_SANDWICH = 14,
-};
-
 /**
  * This structure contains a specific variation of a single file out
  * of all the variations it can have that we can have.
@@ -326,16 +315,16 @@
 {
 public:
     AaptSymbolEntry()
-        : isPublic(false), typeCode(TYPE_UNKNOWN)
+        : isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
     {
     }
     AaptSymbolEntry(const String8& _name)
-        : name(_name), isPublic(false), typeCode(TYPE_UNKNOWN)
+        : name(_name), isPublic(false), isJavaSymbol(false), typeCode(TYPE_UNKNOWN)
     {
     }
     AaptSymbolEntry(const AaptSymbolEntry& o)
         : name(o.name), sourcePos(o.sourcePos), isPublic(o.isPublic)
-        , comment(o.comment), typeComment(o.typeComment)
+        , isJavaSymbol(o.isJavaSymbol), comment(o.comment), typeComment(o.typeComment)
         , typeCode(o.typeCode), int32Val(o.int32Val), stringVal(o.stringVal)
     {
     }
@@ -343,6 +332,7 @@
     {
         sourcePos = o.sourcePos;
         isPublic = o.isPublic;
+        isJavaSymbol = o.isJavaSymbol;
         comment = o.comment;
         typeComment = o.typeComment;
         typeCode = o.typeCode;
@@ -355,6 +345,7 @@
     
     SourcePos sourcePos;
     bool isPublic;
+    bool isJavaSymbol;
     
     String16 comment;
     String16 typeComment;
@@ -412,6 +403,15 @@
         return NO_ERROR;
     }
 
+    status_t makeSymbolJavaSymbol(const String8& name, const SourcePos& pos) {
+        if (!check_valid_symbol_name(name, pos, "symbol")) {
+            return BAD_VALUE;
+        }
+        AaptSymbolEntry& sym = edit_symbol(name, &pos);
+        sym.isJavaSymbol = true;
+        return NO_ERROR;
+    }
+
     void appendComment(const String8& name, const String16& comment, const SourcePos& pos) {
         if (comment.size() <= 0) {
             return;
@@ -452,6 +452,8 @@
         return sym;
     }
 
+    status_t applyJavaSymbols(const sp<AaptSymbols>& javaSymbols);
+
     const KeyedVector<String8, AaptSymbolEntry>& getSymbols() const
         { return mSymbols; }
     const DefaultKeyedVector<String8, sp<AaptSymbols> >& getNestedSymbols() const
@@ -520,7 +522,11 @@
     virtual ~AaptAssets() { delete mRes; }
 
     const String8& getPackage() const { return mPackage; }
-    void setPackage(const String8& package) { mPackage = package; mSymbolsPrivatePackage = package; }
+    void setPackage(const String8& package) {
+        mPackage = package;
+        mSymbolsPrivatePackage = package;
+        mHavePrivateSymbols = false;
+    }
 
     const SortedVector<AaptGroupEntry>& getGroupEntries() const;
 
@@ -543,11 +549,22 @@
 
     sp<AaptSymbols> getSymbolsFor(const String8& name);
 
+    sp<AaptSymbols> getJavaSymbolsFor(const String8& name);
+
+    status_t applyJavaSymbols();
+
     const DefaultKeyedVector<String8, sp<AaptSymbols> >& getSymbols() const { return mSymbols; }
 
     String8 getSymbolsPrivatePackage() const { return mSymbolsPrivatePackage; }
-    void setSymbolsPrivatePackage(const String8& pkg) { mSymbolsPrivatePackage = pkg; }
-    
+    void setSymbolsPrivatePackage(const String8& pkg) {
+        mSymbolsPrivatePackage = pkg;
+        mHavePrivateSymbols = mSymbolsPrivatePackage != mPackage;
+    }
+
+    bool havePrivateSymbols() const { return mHavePrivateSymbols; }
+
+    bool isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const;
+
     status_t buildIncludedResources(Bundle* bundle);
     status_t addIncludedResources(const sp<AaptFile>& file);
     const ResTable& getIncludedResources() const;
@@ -587,7 +604,9 @@
     String8 mPackage;
     SortedVector<AaptGroupEntry> mGroupEntries;
     DefaultKeyedVector<String8, sp<AaptSymbols> > mSymbols;
+    DefaultKeyedVector<String8, sp<AaptSymbols> > mJavaSymbols;
     String8 mSymbolsPrivatePackage;
+    bool mHavePrivateSymbols;
 
     Vector<sp<AaptDir> > mResDirs;
 
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 2d1060b..8e3a1c9 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -14,6 +14,18 @@
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
+enum {
+    SDK_CUPCAKE = 3,
+    SDK_DONUT = 4,
+    SDK_ECLAIR = 5,
+    SDK_ECLAIR_0_1 = 6,
+    SDK_MR1 = 7,
+    SDK_FROYO = 8,
+    SDK_HONEYCOMB_MR2 = 13,
+    SDK_ICE_CREAM_SANDWICH = 14,
+    SDK_ICE_CREAM_SANDWICH_MR1 = 15,
+};
+
 /*
  * Things we can do.
  */
@@ -82,7 +94,6 @@
     void setRequireLocalization(bool val) { mRequireLocalization = val; }
     bool getPseudolocalize(void) const { return mPseudolocalize; }
     void setPseudolocalize(bool val) { mPseudolocalize = val; }
-    bool getWantUTF16(void) const { return mWantUTF16; }
     void setWantUTF16(bool val) { mWantUTF16 = val; }
     bool getValues(void) const { return mValues; }
     void setValues(bool val) { mValues = val; }
@@ -103,6 +114,10 @@
     bool getGenDependencies() { return mGenDependencies; }
     void setGenDependencies(bool val) { mGenDependencies = val; }
 
+    bool getUTF16StringsOption() {
+        return mWantUTF16 || !isMinSdkAtLeast(SDK_FROYO);
+    }
+
     /*
      * Input options.
      */
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 89942de..c79e243 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -479,6 +479,11 @@
 #ifndef HAVE_ANDROID_OS
         res.print(bundle->getValues());
 #endif
+
+    } else if (strcmp("strings", option) == 0) {
+        const ResStringPool* pool = res.getTableStringBlock(0);
+        printStringPool(pool);
+
     } else if (strcmp("xmltree", option) == 0) {
         if (bundle->getFileSpecCount() < 3) {
             fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
@@ -1382,7 +1387,7 @@
                 delete dir;
             }
         } else if (strcmp("badger", option) == 0) {
-            printf(CONSOLE_DATA);
+            printf("%s", CONSOLE_DATA);
         } else if (strcmp("configurations", option) == 0) {
             Vector<ResTable_config> configs;
             res.getConfigurations(&configs);
@@ -1612,6 +1617,12 @@
         goto bail;
     }
 
+    // Update symbols with information about which ones are needed as Java symbols.
+    assets->applyJavaSymbols();
+    if (SourcePos::hasErrors()) {
+        goto bail;
+    }
+
     // If we've been asked to generate a dependency file, do that here
     if (bundle->getGenDependencies()) {
         // If this is the packaging step, generate the dependency file next to
@@ -1633,7 +1644,7 @@
     }
 
     // Write out R.java constants
-    if (assets->getPackage() == assets->getSymbolsPrivatePackage()) {
+    if (!assets->havePrivateSymbols()) {
         if (bundle->getCustomPackage() == NULL) {
             // Write the R.java file into the appropriate class directory
             // e.g. gen/com/foo/app/R.java
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 1ecf7da..7eaf528 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -847,8 +847,7 @@
      * request UTF-16 encoding and the parameters of this package
      * allow UTF-8 to be used.
      */
-    if (!bundle->getWantUTF16()
-            && bundle->isMinSdkAtLeast(SDK_FROYO)) {
+    if (!bundle->getUTF16StringsOption()) {
         xmlFlags |= XML_COMPILE_UTF8;
     }
 
@@ -1809,7 +1808,7 @@
         if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) {
             continue;
         }
-        if (!includePrivate && !sym.isPublic) {
+        if (!assets->isJavaSymbol(sym, includePrivate)) {
             continue;
         }
         String16 name(sym.name);
@@ -1865,7 +1864,7 @@
         if (sym.typeCode != AaptSymbolEntry::TYPE_STRING) {
             continue;
         }
-        if (!includePrivate && !sym.isPublic) {
+        if (!assets->isJavaSymbol(sym, includePrivate)) {
             continue;
         }
         String16 name(sym.name);
@@ -1977,7 +1976,8 @@
         "\n"
         "package %s;\n\n", package.string());
 
-        status_t err = writeSymbolClass(fp, assets, includePrivate, symbols, className, 0, bundle->getNonConstantId());
+        status_t err = writeSymbolClass(fp, assets, includePrivate, symbols,
+                className, 0, bundle->getNonConstantId());
         if (err != NO_ERROR) {
             return err;
         }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index fdb39ca..7a0499c 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -753,6 +753,7 @@
     const String16 public16("public");
     const String16 public_padding16("public-padding");
     const String16 private_symbols16("private-symbols");
+    const String16 java_symbol16("java-symbol");
     const String16 add_resource16("add-resource");
     const String16 skip16("skip");
     const String16 eat_comment16("eat-comment");
@@ -1058,6 +1059,49 @@
                 }
                 continue;
 
+            } else if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) {
+                SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
+            
+                String16 type;
+                ssize_t typeIdx = block.indexOfAttribute(NULL, "type");
+                if (typeIdx < 0) {
+                    srcPos.error("A 'type' attribute is required for <public>\n");
+                    hasErrors = localHasErrors = true;
+                }
+                type = String16(block.getAttributeStringValue(typeIdx, &len));
+
+                String16 name;
+                ssize_t nameIdx = block.indexOfAttribute(NULL, "name");
+                if (nameIdx < 0) {
+                    srcPos.error("A 'name' attribute is required for <public>\n");
+                    hasErrors = localHasErrors = true;
+                }
+                name = String16(block.getAttributeStringValue(nameIdx, &len));
+
+                sp<AaptSymbols> symbols = assets->getJavaSymbolsFor(String8("R"));
+                if (symbols != NULL) {
+                    symbols = symbols->addNestedSymbol(String8(type), srcPos);
+                }
+                if (symbols != NULL) {
+                    symbols->makeSymbolJavaSymbol(String8(name), srcPos);
+                    String16 comment(
+                        block.getComment(&len) ? block.getComment(&len) : nulStr);
+                    symbols->appendComment(String8(name), comment, srcPos);
+                } else {
+                    srcPos.error("Unable to create symbols!\n");
+                    hasErrors = localHasErrors = true;
+                }
+
+                while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+                    if (code == ResXMLTree::END_TAG) {
+                        if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) {
+                            break;
+                        }
+                    }
+                }
+                continue;
+
+
             } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
                 SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
             
@@ -2047,7 +2091,8 @@
                                   uint32_t attrID,
                                   const Vector<StringPool::entry_style_span>* style,
                                   String16* outStr, void* accessorCookie,
-                                  uint32_t attrType)
+                                  uint32_t attrType, const String8* configTypeName,
+                                  const ConfigDescription* config)
 {
     String16 finalStr;
 
@@ -2075,10 +2120,19 @@
     if (outValue->dataType == outValue->TYPE_STRING) {
         // Should do better merging styles.
         if (pool) {
-            if (style != NULL && style->size() > 0) {
-                outValue->data = pool->add(finalStr, *style);
+            String8 configStr;
+            if (config != NULL) {
+                configStr = config->toString();
             } else {
-                outValue->data = pool->add(finalStr, true);
+                configStr = "(null)";
+            }
+            NOISY(printf("Adding to pool string style #%d config %s: %s\n",
+                    style != NULL ? style->size() : 0,
+                    configStr.string(), String8(finalStr).string()));
+            if (style != NULL && style->size() > 0) {
+                outValue->data = pool->add(finalStr, *style, configTypeName, config);
+            } else {
+                outValue->data = pool->add(finalStr, true, configTypeName, config);
             }
         } else {
             // Caller will fill this in later.
@@ -2537,16 +2591,19 @@
         return err;
     }
 
+    const ConfigDescription nullConfig;
+
     const size_t N = mOrderedPackages.size();
     size_t pi;
 
     const static String16 mipmap16("mipmap");
 
-    bool useUTF8 = !bundle->getWantUTF16() && bundle->isMinSdkAtLeast(SDK_FROYO);
+    bool useUTF8 = !bundle->getUTF16StringsOption();
 
     // Iterate through all data, collecting all values (strings,
     // references, etc).
     StringPool valueStrings = StringPool(false, useUTF8);
+    Vector<sp<Entry> > allEntries;
     for (pi=0; pi<N; pi++) {
         sp<Package> p = mOrderedPackages.itemAt(pi);
         if (p->getTypes().size() == 0) {
@@ -2567,6 +2624,19 @@
             const String16 typeName(t->getName());
             typeStrings.add(typeName, false);
 
+            // This is a hack to tweak the sorting order of the final strings,
+            // to put stuff that is generally not language-specific first.
+            String8 configTypeName(typeName);
+            if (configTypeName == "drawable" || configTypeName == "layout"
+                    || configTypeName == "color" || configTypeName == "anim"
+                    || configTypeName == "interpolator" || configTypeName == "animator"
+                    || configTypeName == "xml" || configTypeName == "menu"
+                    || configTypeName == "mipmap" || configTypeName == "raw") {
+                configTypeName = "1complex";
+            } else {
+                configTypeName = "2value";
+            }
+
             const bool filterable = (typeName != mipmap16);
 
             const size_t N = t->getOrderedConfigs().size();
@@ -2586,10 +2656,21 @@
                         continue;
                     }
                     e->setNameIndex(keyStrings.add(e->getName(), true));
-                    status_t err = e->prepareFlatten(&valueStrings, this);
+
+                    // If this entry has no values for other configs,
+                    // and is the default config, then it is special.  Otherwise
+                    // we want to add it with the config info.
+                    ConfigDescription* valueConfig = NULL;
+                    if (N != 1 || config == nullConfig) {
+                        valueConfig = &config;
+                    }
+
+                    status_t err = e->prepareFlatten(&valueStrings, this,
+                            &configTypeName, &config);
                     if (err != NO_ERROR) {
                         return err;
                     }
+                    allEntries.add(e);
                 }
             }
         }
@@ -2598,6 +2679,17 @@
         p->setKeyStrings(keyStrings.createStringBlock());
     }
 
+    if (bundle->getOutputAPKFile() != NULL) {
+        // Now we want to sort the value strings for better locality.  This will
+        // cause the positions of the strings to change, so we need to go back
+        // through out resource entries and update them accordingly.  Only need
+        // to do this if actually writing the output file.
+        valueStrings.sortByConfig();
+        for (pi=0; pi<allEntries.size(); pi++) {
+            allEntries[pi]->remapStringValue(&valueStrings);
+        }
+    }
+
     ssize_t strAmt = 0;
     
     // Now build the array of package chunks.
@@ -3137,14 +3229,16 @@
     return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
 }
 
-status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table)
+status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table,
+        const String8* configTypeName, const ConfigDescription* config)
 {
     if (mType == TYPE_ITEM) {
         Item& it = mItem;
         AccessorCookie ac(it.sourcePos, String8(mName), String8(it.value));
         if (!table->stringToValue(&it.parsedValue, strings,
                                   it.value, false, true, 0,
-                                  &it.style, NULL, &ac, mItemFormat)) {
+                                  &it.style, NULL, &ac, mItemFormat,
+                                  configTypeName, config)) {
             return UNKNOWN_ERROR;
         }
     } else if (mType == TYPE_BAG) {
@@ -3155,7 +3249,8 @@
             AccessorCookie ac(it.sourcePos, String8(key), String8(it.value));
             if (!table->stringToValue(&it.parsedValue, strings,
                                       it.value, false, true, it.bagKeyId,
-                                      &it.style, NULL, &ac, it.format)) {
+                                      &it.style, NULL, &ac, it.format,
+                                      configTypeName, config)) {
                 return UNKNOWN_ERROR;
             }
         }
@@ -3167,6 +3262,29 @@
     return NO_ERROR;
 }
 
+status_t ResourceTable::Entry::remapStringValue(StringPool* strings)
+{
+    if (mType == TYPE_ITEM) {
+        Item& it = mItem;
+        if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
+            it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
+        }
+    } else if (mType == TYPE_BAG) {
+        const size_t N = mBag.size();
+        for (size_t i=0; i<N; i++) {
+            Item& it = mBag.editValueAt(i);
+            if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
+                it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
+            }
+        }
+    } else {
+        mPos.error("Error: entry %s is not a single item or a bag.\n",
+                   String8(mName).string());
+        return UNKNOWN_ERROR;
+    }
+    return NO_ERROR;
+}
+
 ssize_t ResourceTable::Entry::flatten(Bundle* bundle, const sp<AaptFile>& data, bool isPublic)
 {
     size_t amt = 0;
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 8123bb3..a3e0666 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -76,6 +76,37 @@
     class Type;
     class Entry;
 
+    struct ConfigDescription : public ResTable_config {
+        ConfigDescription() {
+            memset(this, 0, sizeof(*this));
+            size = sizeof(ResTable_config);
+        }
+        ConfigDescription(const ResTable_config&o) {
+            *static_cast<ResTable_config*>(this) = o;
+            size = sizeof(ResTable_config);
+        }
+        ConfigDescription(const ConfigDescription&o) {
+            *static_cast<ResTable_config*>(this) = o;
+        }
+
+        ConfigDescription& operator=(const ResTable_config& o) {
+            *static_cast<ResTable_config*>(this) = o;
+            size = sizeof(ResTable_config);
+            return *this;
+        }
+        ConfigDescription& operator=(const ConfigDescription& o) {
+            *static_cast<ResTable_config*>(this) = o;
+            return *this;
+        }
+
+        inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
+        inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
+        inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
+        inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
+        inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
+        inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
+    };
+
     ResourceTable(Bundle* bundle, const String16& assetsPackage);
 
     status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);
@@ -183,7 +214,9 @@
                        uint32_t attrID,
                        const Vector<StringPool::entry_style_span>* style = NULL,
                        String16* outStr = NULL, void* accessorCookie = NULL,
-                       uint32_t attrType = ResTable_map::TYPE_ANY);
+                       uint32_t attrType = ResTable_map::TYPE_ANY,
+                       const String8* configTypeName = NULL,
+                       const ConfigDescription* config = NULL);
 
     status_t assignResourceIds();
     status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL);
@@ -305,7 +338,10 @@
         status_t assignResourceIds(ResourceTable* table,
                                    const String16& package);
 
-        status_t prepareFlatten(StringPool* strings, ResourceTable* table);
+        status_t prepareFlatten(StringPool* strings, ResourceTable* table,
+               const String8* configTypeName, const ConfigDescription* config);
+
+        status_t remapStringValue(StringPool* strings);
 
         ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic);
 
@@ -322,37 +358,6 @@
         uint32_t mParentId;
         SourcePos mPos;
     };
-
-    struct ConfigDescription : public ResTable_config {
-        ConfigDescription() {
-            memset(this, 0, sizeof(*this));
-            size = sizeof(ResTable_config);
-        }
-        ConfigDescription(const ResTable_config&o) {
-            *static_cast<ResTable_config*>(this) = o;
-            size = sizeof(ResTable_config);
-        }
-        ConfigDescription(const ConfigDescription&o) {
-            *static_cast<ResTable_config*>(this) = o;
-        }
-        
-        ConfigDescription& operator=(const ResTable_config& o) {
-            *static_cast<ResTable_config*>(this) = o;
-            size = sizeof(ResTable_config);
-            return *this;
-        }
-        ConfigDescription& operator=(const ConfigDescription& o) {
-            *static_cast<ResTable_config*>(this) = o;
-            return *this;
-        }
-        
-        inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
-        inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
-        inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
-        inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
-        inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
-        inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
-    };
     
     class ConfigList : public RefBase {
     public:
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 9a0a1c4..fe88e37 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -5,8 +5,10 @@
 //
 
 #include "StringPool.h"
+#include "ResourceTable.h"
 
 #include <utils/ByteOrder.h>
+#include <utils/SortedVector.h>
 
 #if HAVE_PRINTF_ZD
 #  define ZD "%zd"
@@ -30,31 +32,87 @@
 
 void printStringPool(const ResStringPool* pool)
 {
+    SortedVector<const void*> uniqueStrings;
+    const size_t N = pool->size();
+    for (size_t i=0; i<N; i++) {
+        size_t len;
+        if (pool->isUTF8()) {
+            uniqueStrings.add(pool->string8At(i, &len));
+        } else {
+            uniqueStrings.add(pool->stringAt(i, &len));
+        }
+    }
+
+    printf("String pool of " ZD " unique %s %s strings, " ZD " entries and "
+            ZD " styles using " ZD " bytes:\n",
+            (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16",
+            pool->isSorted() ? "sorted" : "non-sorted",
+            (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes());
+
     const size_t NS = pool->size();
     for (size_t s=0; s<NS; s++) {
-        size_t len;
-        const char *str = (const char*)pool->string8At(s, &len);
-        if (str == NULL) {
-            str = String8(pool->stringAt(s, &len)).string();
-        }
-
-        printf("String #" ZD ": %s\n", (ZD_TYPE) s, str);
+        String8 str = pool->string8ObjectAt(s);
+        printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
     }
 }
 
+String8 StringPool::entry::makeConfigsString() const {
+    String8 configStr(configTypeName);
+    if (configStr.size() > 0) configStr.append(" ");
+    if (configs.size() > 0) {
+        for (size_t j=0; j<configs.size(); j++) {
+            if (j > 0) configStr.append(", ");
+            configStr.append(configs[j].toString());
+        }
+    } else {
+        configStr = "(none)";
+    }
+    return configStr;
+}
+
+int StringPool::entry::compare(const entry& o) const {
+    // Strings with styles go first, to reduce the size of the
+    // styles array.
+    if (hasStyles) {
+        return o.hasStyles ? 0 : -1;
+    }
+    if (o.hasStyles) {
+        return 1;
+    }
+    int comp = configTypeName.compare(o.configTypeName);
+    if (comp != 0) {
+        return comp;
+    }
+    const size_t LHN = configs.size();
+    const size_t RHN = o.configs.size();
+    size_t i=0;
+    while (i < LHN && i < RHN) {
+        comp = configs[i].compareLogical(o.configs[i]);
+        if (comp != 0) {
+            return comp;
+        }
+        i++;
+    }
+    if (LHN < RHN) return -1;
+    else if (LHN > RHN) return 1;
+    return 0;
+}
+
 StringPool::StringPool(bool sorted, bool utf8)
     : mSorted(sorted), mUTF8(utf8), mValues(-1), mIdents(-1)
 {
 }
 
-ssize_t StringPool::add(const String16& value, bool mergeDuplicates)
+ssize_t StringPool::add(const String16& value, bool mergeDuplicates,
+        const String8* configTypeName, const ResTable_config* config)
 {
-    return add(String16(), value, mergeDuplicates);
+    return add(String16(), value, mergeDuplicates, configTypeName, config);
 }
 
-ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans)
+ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans,
+        const String8* configTypeName, const ResTable_config* config)
 {
-    ssize_t res = add(String16(), value, false);
+    ssize_t res = add(String16(), value, false, configTypeName, config);
     if (res >= 0) {
         addStyleSpans(res, spans);
     }
@@ -62,7 +120,7 @@
 }
 
 ssize_t StringPool::add(const String16& ident, const String16& value,
-                        bool mergeDuplicates)
+        bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config)
 {
     if (ident.size() > 0) {
         ssize_t idx = mIdents.valueFor(ident);
@@ -84,20 +142,43 @@
         }
     }
 
+    if (configTypeName != NULL) {
+        entry& ent = mEntries.editItemAt(eidx);
+        NOISY(printf("*** adding config type name %s, was %s\n",
+                configTypeName->string(), ent.configTypeName.string()));
+        if (ent.configTypeName.size() <= 0) {
+            ent.configTypeName = *configTypeName;
+        } else if (ent.configTypeName != *configTypeName) {
+            ent.configTypeName = " ";
+        }
+    }
+
+    if (config != NULL) {
+        // Add this to the set of configs associated with the string.
+        entry& ent = mEntries.editItemAt(eidx);
+        size_t addPos;
+        for (addPos=0; addPos<ent.configs.size(); addPos++) {
+            int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
+            if (cmp >= 0) {
+                if (cmp > 0) {
+                    NOISY(printf("*** inserting config: %s\n", config->toString().string()));
+                    ent.configs.insertAt(*config, addPos);
+                }
+                break;
+            }
+        }
+        if (addPos >= ent.configs.size()) {
+            NOISY(printf("*** adding config: %s\n", config->toString().string()));
+            ent.configs.add(*config);
+        }
+    }
+
     const bool first = vidx < 0;
     if (first || !mergeDuplicates) {
         pos = mEntryArray.add(eidx);
         if (first) {
             vidx = mValues.add(value, pos);
-            const size_t N = mEntryArrayToValues.size();
-            for (size_t i=0; i<N; i++) {
-                size_t& e = mEntryArrayToValues.editItemAt(i);
-                if ((ssize_t)e >= vidx) {
-                    e++;
-                }
-            }
         }
-        mEntryArrayToValues.add(vidx);
         if (!mSorted) {
             entry& ent = mEntries.editItemAt(eidx);
             ent.indices.add(pos);
@@ -147,6 +228,7 @@
 
     entry_style& style = mEntryStyleArray.editItemAt(idx);
     style.spans.add(span);
+    mEntries.editItemAt(mEntryArray[idx]).hasStyles = true;
     return NO_ERROR;
 }
 
@@ -169,6 +251,132 @@
     return mIdents.size();
 }
 
+int StringPool::config_sort(const size_t* lhs, const size_t* rhs, void* state)
+{
+    StringPool* pool = (StringPool*)state;
+    const entry& lhe = pool->mEntries[pool->mEntryArray[*lhs]];
+    const entry& rhe = pool->mEntries[pool->mEntryArray[*rhs]];
+    return lhe.compare(rhe);
+}
+
+void StringPool::sortByConfig()
+{
+    LOG_ALWAYS_FATAL_IF(mSorted, "Can't sort string pool containing identifiers.");
+    LOG_ALWAYS_FATAL_IF(mIdents.size() > 0, "Can't sort string pool containing identifiers.");
+    LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted.");
+
+    const size_t N = mEntryArray.size();
+
+    // This is a vector that starts out with a 1:1 mapping to entries
+    // in the array, which we will sort to come up with the desired order.
+    // At that point it maps from the new position in the array to the
+    // original position the entry appeared.
+    Vector<size_t> newPosToOriginalPos;
+    for (size_t i=0; i<mEntryArray.size(); i++) {
+        newPosToOriginalPos.add(i);
+    }
+
+    // Sort the array.
+    NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
+    newPosToOriginalPos.sort(config_sort, this);
+    NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));
+
+    // Create the reverse mapping from the original position in the array
+    // to the new position where it appears in the sorted array.  This is
+    // so that clients can re-map any positions they had previously stored.
+    mOriginalPosToNewPos = newPosToOriginalPos;
+    for (size_t i=0; i<N; i++) {
+        mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i;
+    }
+
+#if 0
+    SortedVector<entry> entries;
+
+    for (size_t i=0; i<N; i++) {
+        printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
+                mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
+        entries.add(mEntries[mEntryArray[i]]);
+    }
+
+    for (size_t i=0; i<entries.size(); i++) {
+        printf("Sorted config #%d: %s\n", i,
+                entries[i].makeConfigsString().string());
+    }
+#endif
+
+    // Now we rebuild the arrays.
+    Vector<entry> newEntries;
+    Vector<size_t> newEntryArray;
+    Vector<entry_style> newEntryStyleArray;
+    DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset;
+
+    for (size_t i=0; i<N; i++) {
+        // We are filling in new offset 'i'; oldI is where we can find it
+        // in the original data structure.
+        size_t oldI = newPosToOriginalPos[i];
+        // This is the actual entry associated with the old offset.
+        const entry& oldEnt = mEntries[mEntryArray[oldI]];
+        // This is the same entry the last time we added it to the
+        // new entry array, if any.
+        ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI);
+        size_t newOffset;
+        if (newIndexOfOffset < 0) {
+            // This is the first time we have seen the entry, so add
+            // it.
+            newOffset = newEntries.add(oldEnt);
+            newEntries.editItemAt(newOffset).indices.clear();
+        } else {
+            // We have seen this entry before, use the existing one
+            // instead of adding it again.
+            newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset);
+        }
+        // Update the indices to include this new position.
+        newEntries.editItemAt(newOffset).indices.add(i);
+        // And add the offset of the entry to the new entry array.
+        newEntryArray.add(newOffset);
+        // Add any old style to the new style array.
+        if (mEntryStyleArray.size() > 0) {
+            if (oldI < mEntryStyleArray.size()) {
+                newEntryStyleArray.add(mEntryStyleArray[oldI]);
+            } else {
+                newEntryStyleArray.add(entry_style());
+            }
+        }
+    }
+
+    // Now trim any entries at the end of the new style array that are
+    // not needed.
+    for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) {
+        const entry_style& style = newEntryStyleArray[i];
+        if (style.spans.size() > 0) {
+            // That's it.
+            break;
+        }
+        // This one is not needed; remove.
+        newEntryStyleArray.removeAt(i);
+    }
+
+    // All done, install the new data structures and upate mValues with
+    // the new positions.
+    mEntries = newEntries;
+    mEntryArray = newEntryArray;
+    mEntryStyleArray = newEntryStyleArray;
+    mValues.clear();
+    for (size_t i=0; i<mEntries.size(); i++) {
+        const entry& ent = mEntries[i];
+        mValues.add(ent.value, ent.indices[0]);
+    }
+
+#if 0
+    printf("FINAL SORTED STRING CONFIGS:\n");
+    for (size_t i=0; i<mEntries.size(); i++) {
+        const entry& ent = mEntries[i];
+        printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
+                String8(ent.value).string());
+    }
+#endif
+}
+
 sp<AaptFile> StringPool::createStringBlock()
 {
     sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(),
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 7275259..255bdbf 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -40,12 +40,28 @@
 public:
     struct entry {
         entry() : offset(0) { }
-        entry(const String16& _value) : value(_value), offset(0) { }
-        entry(const entry& o) : value(o.value), offset(o.offset), indices(o.indices) { }
+        entry(const String16& _value) : value(_value), offset(0), hasStyles(false) { }
+        entry(const entry& o) : value(o.value), offset(o.offset),
+                hasStyles(o.hasStyles), indices(o.indices),
+                configTypeName(o.configTypeName), configs(o.configs) { }
 
         String16 value;
         size_t offset;
+        bool hasStyles;
         Vector<size_t> indices;
+        String8 configTypeName;
+        Vector<ResTable_config> configs;
+
+        String8 makeConfigsString() const;
+
+        int compare(const entry& o) const;
+
+        inline bool operator<(const entry& o) const { return compare(o) < 0; }
+        inline bool operator<=(const entry& o) const { return compare(o) <= 0; }
+        inline bool operator==(const entry& o) const { return compare(o) == 0; }
+        inline bool operator!=(const entry& o) const { return compare(o) != 0; }
+        inline bool operator>=(const entry& o) const { return compare(o) >= 0; }
+        inline bool operator>(const entry& o) const { return compare(o) > 0; }
     };
 
     struct entry_style_span {
@@ -84,12 +100,15 @@
      * if this string pool is sorted, the returned index will not be valid
      * when the pool is finally written.
      */
-    ssize_t add(const String16& value, bool mergeDuplicates = false);
+    ssize_t add(const String16& value, bool mergeDuplicates = false,
+            const String8* configTypeName = NULL, const ResTable_config* config = NULL);
 
-    ssize_t add(const String16& value, const Vector<entry_style_span>& spans);
+    ssize_t add(const String16& value, const Vector<entry_style_span>& spans,
+            const String8* configTypeName = NULL, const ResTable_config* config = NULL);
 
     ssize_t add(const String16& ident, const String16& value,
-                bool mergeDuplicates = false);
+                bool mergeDuplicates = false,
+                const String8* configTypeName = NULL, const ResTable_config* config = NULL);
 
     status_t addStyleSpan(size_t idx, const String16& name,
                           uint32_t start, uint32_t end);
@@ -102,6 +121,18 @@
 
     size_t countIdentifiers() const;
 
+    // Sort the contents of the string block by the configuration associated
+    // with each item.  After doing this you can use mapOriginalPosToNewPos()
+    // to find out the new position given the position originall returned by
+    // add().
+    void sortByConfig();
+
+    // For use after sortByConfig() to map from the original position of
+    // a string to its new sorted position.
+    size_t mapOriginalPosToNewPos(size_t originalPos) const {
+        return mOriginalPosToNewPos.itemAt(originalPos);
+    }
+
     sp<AaptFile> createStringBlock();
 
     status_t writeStringBlock(const sp<AaptFile>& pool);
@@ -125,27 +156,41 @@
     const Vector<size_t>* offsetsForString(const String16& val) const;
 
 private:
+    static int config_sort(const size_t* lhs, const size_t* rhs, void* state);
+
     const bool                              mSorted;
     const bool                              mUTF8;
-    // Raw array of unique strings, in some arbitrary order.
+
+    // The following data structures represent the actual structures
+    // that will be generated for the final string pool.
+
+    // Raw array of unique strings, in some arbitrary order.  This is the
+    // actual strings that appear in the final string pool, in the order
+    // that they will be written.
     Vector<entry>                           mEntries;
     // Array of indices into mEntries, in the order they were
     // added to the pool.  This can be different than mEntries
     // if the same string was added multiple times (it will appear
     // once in mEntries, with multiple occurrences in this array).
+    // This is the lookup array that will be written for finding
+    // the string for each offset/position in the string pool.
     Vector<size_t>                          mEntryArray;
     // Optional style span information associated with each index of
     // mEntryArray.
     Vector<entry_style>                     mEntryStyleArray;
-    // Mapping from indices in mEntryArray to indices in mValues.
-    Vector<size_t>                          mEntryArrayToValues;
+
+    // The following data structures are used for book-keeping as the
+    // string pool is constructed.
+
     // Unique set of all the strings added to the pool, mapped to
     // the first index of mEntryArray where the value was added.
     DefaultKeyedVector<String16, ssize_t>   mValues;
     // Unique set of all (optional) identifiers of strings in the
     // pool, mapping to indices in mEntries.
     DefaultKeyedVector<String16, ssize_t>   mIdents;
-
+    // This array maps from the original position a string was placed at
+    // in mEntryArray to its new position after being sorted with sortByConfig().
+    Vector<size_t>                          mOriginalPosToNewPos;
 };
 
 #endif
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index c0d7427..95a68d1 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -45,6 +45,7 @@
 
 static const String16 RESOURCES_PREFIX(RESOURCES_ROOT_NAMESPACE);
 static const String16 RESOURCES_PRV_PREFIX(RESOURCES_ROOT_PRV_NAMESPACE);
+static const String16 RESOURCES_TOOLS_NAMESPACE("http://schemas.android.com/tools");
 
 String16 getNamespaceResourcePackage(String16 namespaceUri, bool* outIsPublic)
 {
@@ -761,13 +762,16 @@
         SourcePos(mFilename, getStartLineNumber()).error("Child to CDATA node.");
         return UNKNOWN_ERROR;
     }
-    attribute_entry e;
-    e.index = mNextAttributeIndex++;
-    e.ns = ns;
-    e.name = name;
-    e.string = value;
-    mAttributes.add(e);
-    mAttributeOrder.add(e.index, mAttributes.size()-1);
+
+    if (ns != RESOURCES_TOOLS_NAMESPACE) {
+        attribute_entry e;
+        e.index = mNextAttributeIndex++;
+        e.ns = ns;
+        e.name = name;
+        e.string = value;
+        mAttributes.add(e);
+        mAttributeOrder.add(e.index, mAttributes.size()-1);
+    }
     return NO_ERROR;
 }
 
@@ -1215,11 +1219,13 @@
     collect_attr_strings(dest, outResIds, true);
     
     int i;
-    if (mNamespacePrefix.size() > 0) {
-        dest->add(mNamespacePrefix, true);
-    }
-    if (mNamespaceUri.size() > 0) {
-        dest->add(mNamespaceUri, true);
+    if (RESOURCES_TOOLS_NAMESPACE != mNamespaceUri) {
+        if (mNamespacePrefix.size() > 0) {
+            dest->add(mNamespacePrefix, true);
+        }
+        if (mNamespaceUri.size() > 0) {
+            dest->add(mNamespaceUri, true);
+        }
     }
     if (mElementName.size() > 0) {
         dest->add(mElementName, true);
@@ -1338,6 +1344,7 @@
     const void* extData = NULL;
     size_t extSize = 0;
     ResXMLTree_attribute attr;
+    bool writeCurrentNode = true;
 
     const size_t NA = mAttributes.size();
     const size_t NC = mChildren.size();
@@ -1350,7 +1357,7 @@
     const String16 style16("style");
 
     const type type = getType();
-    
+
     memset(&node, 0, sizeof(node));
     memset(&attr, 0, sizeof(attr));
     node.header.headerSize = htods(sizeof(node));
@@ -1395,17 +1402,21 @@
             }
         }
     } else if (type == TYPE_NAMESPACE) {
-        node.header.type = htods(RES_XML_START_NAMESPACE_TYPE);
-        extData = &namespaceExt;
-        extSize = sizeof(namespaceExt);
-        memset(&namespaceExt, 0, sizeof(namespaceExt));
-        if (mNamespacePrefix.size() > 0) {
-            namespaceExt.prefix.index = htodl(strings.offsetForString(mNamespacePrefix));
+        if (mNamespaceUri == RESOURCES_TOOLS_NAMESPACE) {
+            writeCurrentNode = false;
         } else {
-            namespaceExt.prefix.index = htodl((uint32_t)-1);
+            node.header.type = htods(RES_XML_START_NAMESPACE_TYPE);
+            extData = &namespaceExt;
+            extSize = sizeof(namespaceExt);
+            memset(&namespaceExt, 0, sizeof(namespaceExt));
+            if (mNamespacePrefix.size() > 0) {
+                namespaceExt.prefix.index = htodl(strings.offsetForString(mNamespacePrefix));
+            } else {
+                namespaceExt.prefix.index = htodl((uint32_t)-1);
+            }
+            namespaceExt.prefix.index = htodl(strings.offsetForString(mNamespacePrefix));
+            namespaceExt.uri.index = htodl(strings.offsetForString(mNamespaceUri));
         }
-        namespaceExt.prefix.index = htodl(strings.offsetForString(mNamespacePrefix));
-        namespaceExt.uri.index = htodl(strings.offsetForString(mNamespaceUri));
         LOG_ALWAYS_FATAL_IF(NA != 0, "Namespace nodes can't have attributes!");
     } else if (type == TYPE_CDATA) {
         node.header.type = htods(RES_XML_CDATA_TYPE);
@@ -1422,9 +1433,11 @@
 
     node.header.size = htodl(sizeof(node) + extSize + (sizeof(attr)*NA));
 
-    dest->writeData(&node, sizeof(node));
-    if (extSize > 0) {
-        dest->writeData(extData, extSize);
+    if (writeCurrentNode) {
+        dest->writeData(&node, sizeof(node));
+        if (extSize > 0) {
+            dest->writeData(extData, extSize);
+        }
     }
 
     for (i=0; i<NA; i++) {
@@ -1476,12 +1489,14 @@
         dest->writeData(&node, sizeof(node));
         dest->writeData(&endElementExt, sizeof(endElementExt));
     } else if (type == TYPE_NAMESPACE) {
-        node.header.type = htods(RES_XML_END_NAMESPACE_TYPE);
-        node.lineNumber = htodl(getEndLineNumber());
-        node.comment.index = htodl((uint32_t)-1);
-        node.header.size = htodl(sizeof(node)+extSize);
-        dest->writeData(&node, sizeof(node));
-        dest->writeData(extData, extSize);
+        if (writeCurrentNode) {
+            node.header.type = htods(RES_XML_END_NAMESPACE_TYPE);
+            node.lineNumber = htodl(getEndLineNumber());
+            node.comment.index = htodl((uint32_t)-1);
+            node.header.size = htodl(sizeof(node)+extSize);
+            dest->writeData(&node, sizeof(node));
+            dest->writeData(extData, extSize);
+        }
     }
 
     return NO_ERROR;
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
index 752ef7c..bfa6765 100755
--- a/tools/aidl/AST.cpp
+++ b/tools/aidl/AST.cpp
@@ -111,6 +111,21 @@
     fprintf(to, "%s", this->value.c_str());
 }
 
+StringLiteralExpression::StringLiteralExpression(const string& v)
+    :value(v)
+{
+}
+
+StringLiteralExpression::~StringLiteralExpression()
+{
+}
+
+void
+StringLiteralExpression::Write(FILE* to)
+{
+    fprintf(to, "\"%s\"", this->value.c_str());
+}
+
 Variable::Variable()
     :type(NULL),
      name(),
@@ -277,6 +292,17 @@
 {
 }
 
+MethodCall::MethodCall(const string& n, int argc = 0, ...)
+    :obj(NULL),
+     clazz(NULL),
+     name(n)
+{
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
 MethodCall::MethodCall(Expression* o, const string& n)
     :obj(o),
      clazz(NULL),
@@ -367,11 +393,29 @@
 {
 }
 
+NewExpression::NewExpression(Type* t, int argc = 0, ...)
+    :type(t)
+{
+  va_list args;
+  va_start(args, argc);
+  init(argc, args);
+  va_end(args);
+}
+
 NewExpression::~NewExpression()
 {
 }
 
 void
+NewExpression::init(int n, va_list args)
+{
+    for (int i=0; i<n; i++) {
+        Expression* expression = (Expression*)va_arg(args, void*);
+        this->arguments.push_back(expression);
+    }
+}
+
+void
 NewExpression::Write(FILE* to)
 {
     fprintf(to, "new %s(", this->type->InstantiableName().c_str());
@@ -636,6 +680,20 @@
     fprintf(to, "}\n");
 }
 
+Break::Break()
+{
+}
+
+Break::~Break()
+{
+}
+
+void
+Break::Write(FILE* to)
+{
+    fprintf(to, "break;\n");
+}
+
 Method::Method()
     :ClassElement(),
      modifiers(0),
@@ -678,7 +736,7 @@
         fprintf(to, "%s\n", this->comment.c_str());
     }
 
-    WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
+    WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
 
     if (this->returnType != NULL) {
         string dim;
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index 3156356..ead5e7a 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -54,6 +54,16 @@
     virtual void Write(FILE* to);
 };
 
+// TODO: also escape the contents.  not needed for now
+struct StringLiteralExpression : public Expression
+{
+    string value;
+
+    StringLiteralExpression(const string& value);
+    virtual ~StringLiteralExpression();
+    virtual void Write(FILE* to);
+};
+
 struct Variable : public Expression
 {
     Type* type;
@@ -104,7 +114,7 @@
     virtual void Write(FILE* to) = 0;
 };
 
-struct StatementBlock
+struct StatementBlock : public Statement
 {
     vector<Statement*> statements;
 
@@ -146,6 +156,7 @@
     vector<string> exceptions;
 
     MethodCall(const string& name);
+    MethodCall(const string& name, int argc, ...);
     MethodCall(Expression* obj, const string& name);
     MethodCall(Type* clazz, const string& name);
     MethodCall(Expression* obj, const string& name, int argc, ...);
@@ -174,8 +185,12 @@
     vector<Expression*> arguments;
 
     NewExpression(Type* type);
+    NewExpression(Type* type, int argc, ...);
     virtual ~NewExpression();
     virtual void Write(FILE* to);
+
+private:
+    void init(int n, va_list args);
 };
 
 struct NewArrayExpression : public Expression
@@ -292,6 +307,13 @@
     virtual void Write(FILE* to);
 };
 
+struct Break : public Statement
+{
+    Break();
+    virtual ~Break();
+    virtual void Write(FILE* to);
+};
+
 struct Method : public ClassElement
 {
     string comment;
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index 2ad0728..77d46ab 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -17,7 +17,9 @@
 	search_path.cpp \
 	AST.cpp \
 	Type.cpp \
-	generate_java.cpp
+	generate_java.cpp \
+	generate_java_binder.cpp \
+	generate_java_rpc.cpp
 
 LOCAL_CFLAGS := -g
 LOCAL_MODULE := aidl
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index 6b69864..42e1226 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -11,6 +11,7 @@
 Type* FLOAT_TYPE;
 Type* DOUBLE_TYPE;
 Type* STRING_TYPE;
+Type* OBJECT_TYPE;
 Type* CHAR_SEQUENCE_TYPE;
 Type* TEXT_UTILS_TYPE;
 Type* REMOTE_EXCEPTION_TYPE;
@@ -21,9 +22,13 @@
 Type* BINDER_PROXY_TYPE;
 Type* PARCEL_TYPE;
 Type* PARCELABLE_INTERFACE_TYPE;
+Type* CONTEXT_TYPE;
 Type* MAP_TYPE;
 Type* LIST_TYPE;
 Type* CLASSLOADER_TYPE;
+Type* RPC_DATA_TYPE;
+Type* RPC_ERROR_TYPE;
+Type* EVENT_FAKE_TYPE;
 
 Expression* NULL_VALUE;
 Expression* THIS_VALUE;
@@ -34,38 +39,48 @@
 void
 register_base_types()
 {
-    VOID_TYPE = new BasicType("void", "XXX", "XXX", "XXX", "XXX", "XXX");
+    VOID_TYPE = new BasicType("void",
+            "XXX", "XXX", "XXX", "XXX", "XXX",
+            "XXX", "XXX", "XXX", "XXX", "XXX");
     NAMES.Add(VOID_TYPE);
 
     BOOLEAN_TYPE = new BooleanType();
     NAMES.Add(BOOLEAN_TYPE);
 
-    BYTE_TYPE = new BasicType("byte", "writeByte", "readByte",
-                "writeByteArray", "createByteArray", "readByteArray");
+    BYTE_TYPE = new BasicType("byte",
+            "writeByte", "readByte", "writeByteArray", "createByteArray", "readByteArray",
+            "putByte", "getByte", "putByteArray", "createByteArray", "getByteArray");
     NAMES.Add(BYTE_TYPE);
 
     CHAR_TYPE = new CharType();
     NAMES.Add(CHAR_TYPE);
 
-    INT_TYPE = new BasicType("int", "writeInt", "readInt",
-                "writeIntArray", "createIntArray", "readIntArray");
+    INT_TYPE = new BasicType("int",
+            "writeInt", "readInt", "writeIntArray", "createIntArray", "readIntArray",
+            "putInteger", "getInteger", "putIntegerArray", "createIntegerArray", "getIntegerArray");
     NAMES.Add(INT_TYPE);
 
-    LONG_TYPE = new BasicType("long", "writeLong", "readLong",
-                "writeLongArray", "createLongArray", "readLongArray");
+    LONG_TYPE = new BasicType("long",
+            "writeLong", "readLong", "writeLongArray", "createLongArray", "readLongArray",
+            "putLong", "getLong", "putLongArray", "createLongArray", "getLongArray");
     NAMES.Add(LONG_TYPE);
 
-    FLOAT_TYPE = new BasicType("float", "writeFloat", "readFloat",
-                "writeFloatArray", "createFloatArray", "readFloatArray");
+    FLOAT_TYPE = new BasicType("float",
+            "writeFloat", "readFloat", "writeFloatArray", "createFloatArray", "readFloatArray",
+            "putFloat", "getFloat", "putFloatArray", "createFloatArray", "getFloatArray");
     NAMES.Add(FLOAT_TYPE);
 
-    DOUBLE_TYPE = new BasicType("double", "writeDouble", "readDouble",
-                "writeDoubleArray", "createDoubleArray", "readDoubleArray");
+    DOUBLE_TYPE = new BasicType("double",
+            "writeDouble", "readDouble", "writeDoubleArray", "createDoubleArray", "readDoubleArray",
+            "putDouble", "getDouble", "putDoubleArray", "createDoubleArray", "getDoubleArray");
     NAMES.Add(DOUBLE_TYPE);
 
     STRING_TYPE = new StringType();
     NAMES.Add(STRING_TYPE);
 
+    OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false, false);
+    NAMES.Add(OBJECT_TYPE);
+
     CHAR_SEQUENCE_TYPE = new CharSequenceType();
     NAMES.Add(CHAR_SEQUENCE_TYPE);
 
@@ -75,8 +90,7 @@
     LIST_TYPE = new ListType();
     NAMES.Add(LIST_TYPE);
 
-    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils",
-                                    Type::BUILT_IN, false, false);
+    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false, false);
     NAMES.Add(TEXT_UTILS_TYPE);
 
     REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
@@ -103,6 +117,19 @@
     PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
     NAMES.Add(PARCELABLE_INTERFACE_TYPE);
 
+    CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false);
+    NAMES.Add(CONTEXT_TYPE);
+
+    RPC_DATA_TYPE = new RpcDataType();
+    NAMES.Add(RPC_DATA_TYPE);
+
+    RPC_ERROR_TYPE = new UserDataType("com.android.athome.rpc", "RpcError",
+                                    true, __FILE__, __LINE__);
+    NAMES.Add(RPC_ERROR_TYPE);
+
+    EVENT_FAKE_TYPE = new Type("event", Type::BUILT_IN, false, false, false);
+    NAMES.Add(EVENT_FAKE_TYPE);
+
     CLASSLOADER_TYPE = new ClassLoaderType();
     NAMES.Add(CLASSLOADER_TYPE);
 
@@ -129,27 +156,30 @@
 
 // ================================================================
 
-Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
+Type::Type(const string& name, int kind, bool canWriteToParcel, bool canWriteToRpcData,
+        bool canBeOut)
     :m_package(),
      m_name(name),
      m_declFile(""),
      m_declLine(-1),
      m_kind(kind),
      m_canWriteToParcel(canWriteToParcel),
+     m_canWriteToRpcData(canWriteToRpcData),
      m_canBeOut(canBeOut)
 {
     m_qualifiedName = name;
 }
 
 Type::Type(const string& package, const string& name,
-            int kind, bool canWriteToParcel, bool canBeOut,
-            const string& declFile, int declLine)
+            int kind, bool canWriteToParcel, bool canWriteToRpcData,
+            bool canBeOut, const string& declFile, int declLine)
     :m_package(package),
      m_name(name),
      m_declFile(declFile),
      m_declLine(declLine),
      m_kind(kind),
      m_canWriteToParcel(canWriteToParcel),
+     m_canWriteToRpcData(canWriteToRpcData),
      m_canBeOut(canBeOut)
 {
     if (package.length() > 0) {
@@ -182,6 +212,12 @@
 }
 
 string
+Type::RpcCreatorName() const
+{
+    return "";
+}
+
+string
 Type::InstantiableName() const
 {
     return QualifiedName();
@@ -244,6 +280,26 @@
 }
 
 void
+Type::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* WriteToRpcData error "
+                + m_qualifiedName + " */"));
+}
+
+void
+Type::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
+            __FILE__, __LINE__, m_qualifiedName.c_str());
+    addTo->Add(new LiteralExpression("/* ReadFromRpcData error "
+                + m_qualifiedName + " */"));
+}
+
+void
 Type::SetQualifiedName(const string& qualified)
 {
     m_qualifiedName = qualified;
@@ -264,29 +320,35 @@
 
 // ================================================================
 
-BasicType::BasicType(const string& name, const string& marshallMethod,
-                     const string& unmarshallMethod,
-                     const string& writeArray, const string& createArray,
-                     const string& readArray)
-    :Type(name, BUILT_IN, true, false),
-     m_marshallMethod(marshallMethod),
-     m_unmarshallMethod(unmarshallMethod),
-     m_writeArrayMethod(writeArray),
-     m_createArrayMethod(createArray),
-     m_readArrayMethod(readArray)
+BasicType::BasicType(const string& name, const string& marshallParcel,
+          const string& unmarshallParcel, const string& writeArrayParcel,
+          const string& createArrayParcel, const string& readArrayParcel,
+          const string& marshallRpc, const string& unmarshallRpc,
+          const string& writeArrayRpc, const string& createArrayRpc, const string& readArrayRpc)
+    :Type(name, BUILT_IN, true, true, false),
+     m_marshallParcel(marshallParcel),
+     m_unmarshallParcel(unmarshallParcel),
+     m_writeArrayParcel(writeArrayParcel),
+     m_createArrayParcel(createArrayParcel),
+     m_readArrayParcel(readArrayParcel),
+     m_marshallRpc(marshallRpc),
+     m_unmarshallRpc(unmarshallRpc),
+     m_writeArrayRpc(writeArrayRpc),
+     m_createArrayRpc(createArrayRpc),
+     m_readArrayRpc(readArrayRpc)
 {
 }
 
 void
 BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
 {
-    addTo->Add(new MethodCall(parcel, m_marshallMethod, 1, v));
+    addTo->Add(new MethodCall(parcel, m_marshallParcel, 1, v));
 }
 
 void
 BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
 {
-    addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallMethod)));
+    addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel)));
 }
 
 bool
@@ -298,27 +360,40 @@
 void
 BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
 {
-    addTo->Add(new MethodCall(parcel, m_writeArrayMethod, 1, v));
+    addTo->Add(new MethodCall(parcel, m_writeArrayParcel, 1, v));
 }
 
 void
 BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
                             Variable* parcel, Variable**)
 {
-    addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayMethod)));
+    addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel)));
 }
 
 void
 BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
 {
-    addTo->Add(new MethodCall(parcel, m_readArrayMethod, 1, v));
+    addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
 }
 
+void
+BasicType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, m_marshallRpc, 2, k, v));
+}
+
+void
+BasicType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, m_unmarshallRpc, 1, k)));
+}
 
 // ================================================================
 
 BooleanType::BooleanType()
-    :Type("boolean", BUILT_IN, true, false)
+    :Type("boolean", BUILT_IN, true, true, false)
 {
 }
 
@@ -362,11 +437,24 @@
     addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
 }
 
+void
+BooleanType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putBoolean", 2, k, v));
+}
+
+void
+BooleanType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getBoolean", 1, k)));
+}
 
 // ================================================================
 
 CharType::CharType()
-    :Type("char", BUILT_IN, true, false)
+    :Type("char", BUILT_IN, true, true, false)
 {
 }
 
@@ -408,10 +496,24 @@
     addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
 }
 
+void
+CharType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putChar", 2, k, v));
+}
+
+void
+CharType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getChar", 1, k)));
+}
+
 // ================================================================
 
 StringType::StringType()
-    :Type("java.lang", "String", BUILT_IN, true, false)
+    :Type("java.lang", "String", BUILT_IN, true, true, false)
 {
 }
 
@@ -458,10 +560,24 @@
     addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
 }
 
+void
+StringType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putString", 2, k, v));
+}
+
+void
+StringType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, Variable**)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getString", 1, k)));
+}
+
 // ================================================================
 
 CharSequenceType::CharSequenceType()
-    :Type("java.lang", "CharSequence", BUILT_IN, true, false)
+    :Type("java.lang", "CharSequence", BUILT_IN, true, true, false)
 {
 }
 
@@ -521,7 +637,7 @@
 // ================================================================
 
 RemoteExceptionType::RemoteExceptionType()
-    :Type("android.os", "RemoteException", BUILT_IN, false, false)
+    :Type("android.os", "RemoteException", BUILT_IN, false, false, false)
 {
 }
 
@@ -540,7 +656,7 @@
 // ================================================================
 
 RuntimeExceptionType::RuntimeExceptionType()
-    :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
+    :Type("java.lang", "RuntimeException", BUILT_IN, false, false, false)
 {
 }
 
@@ -560,7 +676,7 @@
 // ================================================================
 
 IBinderType::IBinderType()
-    :Type("android.os", "IBinder", BUILT_IN, true, false)
+    :Type("android.os", "IBinder", BUILT_IN, true, false, false)
 {
 }
 
@@ -599,7 +715,7 @@
 // ================================================================
 
 IInterfaceType::IInterfaceType()
-    :Type("android.os", "IInterface", BUILT_IN, false, false)
+    :Type("android.os", "IInterface", BUILT_IN, false, false, false)
 {
 }
 
@@ -619,7 +735,7 @@
 // ================================================================
 
 BinderType::BinderType()
-    :Type("android.os", "Binder", BUILT_IN, false, false)
+    :Type("android.os", "Binder", BUILT_IN, false, false, false)
 {
 }
 
@@ -640,7 +756,7 @@
 // ================================================================
 
 BinderProxyType::BinderProxyType()
-    :Type("android.os", "BinderProxy", BUILT_IN, false, false)
+    :Type("android.os", "BinderProxy", BUILT_IN, false, false, false)
 {
 }
 
@@ -661,7 +777,7 @@
 // ================================================================
 
 ParcelType::ParcelType()
-    :Type("android.os", "Parcel", BUILT_IN, false, false)
+    :Type("android.os", "Parcel", BUILT_IN, false, false, false)
 {
 }
 
@@ -680,7 +796,7 @@
 // ================================================================
 
 ParcelableInterfaceType::ParcelableInterfaceType()
-    :Type("android.os", "Parcelable", BUILT_IN, false, false)
+    :Type("android.os", "Parcelable", BUILT_IN, false, false, false)
 {
 }
 
@@ -699,7 +815,7 @@
 // ================================================================
 
 MapType::MapType()
-    :Type("java.util", "Map", BUILT_IN, true, true)
+    :Type("java.util", "Map", BUILT_IN, true, false, true)
 {
 }
 
@@ -729,8 +845,7 @@
 }
 
 void
-MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
-                    Variable* parcel, Variable** cl)
+MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
 {
     EnsureClassLoader(addTo, cl);
     addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
@@ -740,7 +855,7 @@
 // ================================================================
 
 ListType::ListType()
-    :Type("java.util", "List", BUILT_IN, true, true)
+    :Type("java.util", "List", BUILT_IN, true, true, true)
 {
 }
 
@@ -771,24 +886,44 @@
     addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
 }
 
+void
+ListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putList", 2, k, v));
+}
+
+void
+ListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getList", 1, k)));
+}
 
 // ================================================================
 
-ParcelableType::ParcelableType(const string& package, const string& name,
-                        bool builtIn, const string& declFile, int declLine)
-    :Type(package, name, builtIn ? BUILT_IN : PARCELABLE, true, true,
-            declFile, declLine)
+UserDataType::UserDataType(const string& package, const string& name,
+                        bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+                        const string& declFile, int declLine)
+    :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel, canWriteToRpcData,
+            true, declFile, declLine)
 {
 }
 
 string
-ParcelableType::CreatorName() const
+UserDataType::CreatorName() const
 {
     return QualifiedName() + ".CREATOR";
 }
 
+string
+UserDataType::RpcCreatorName() const
+{
+    return QualifiedName() + ".RPC_CREATOR";
+}
+
 void
-ParcelableType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
 {
     // if (v != null) {
     //     parcel.writeInt(1);
@@ -811,7 +946,7 @@
 }
 
 void
-ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+UserDataType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
 {
     // if (0 != parcel.readInt()) {
     //     v = CLASS.CREATOR.createFromParcel(parcel)
@@ -832,7 +967,7 @@
 }
 
 void
-ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v,
+UserDataType::ReadFromParcel(StatementBlock* addTo, Variable* v,
                     Variable* parcel, Variable**)
 {
     // TODO: really, we don't need to have this extra check, but we
@@ -848,20 +983,20 @@
 }
 
 bool
-ParcelableType::CanBeArray() const
+UserDataType::CanBeArray() const
 {
     return true;
 }
 
 void
-ParcelableType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
+UserDataType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
 {
     addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
                 BuildWriteToParcelFlags(flags)));
 }
 
 void
-ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
+UserDataType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
                             Variable* parcel, Variable**)
 {
     string creator = v->type->QualifiedName() + ".CREATOR";
@@ -870,20 +1005,36 @@
 }
 
 void
-ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
+UserDataType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
 {
     string creator = v->type->QualifiedName() + ".CREATOR";
     addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
                     v, new LiteralExpression(creator)));
 }
 
+void
+UserDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags)
+{
+    // data.putFlattenable(k, v);
+    addTo->Add(new MethodCall(data, "putFlattenable", 2, k, v));
+}
+
+void
+UserDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl)
+{
+    // data.getFlattenable(k, CLASS.RPC_CREATOR);
+    addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenable", 2, k,
+                new FieldVariable(v->type, "RPC_CREATOR"))));
+}
 
 // ================================================================
 
 InterfaceType::InterfaceType(const string& package, const string& name,
                         bool builtIn, bool oneway,
                         const string& declFile, int declLine)
-    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
+    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false, false,
                         declFile, declLine)
     ,m_oneway(oneway)
 {
@@ -922,7 +1073,7 @@
 
 GenericType::GenericType(const string& package, const string& name,
                          const vector<Type*>& args)
-    :Type(package, name, BUILT_IN, true, true)
+    :Type(package, name, BUILT_IN, true, true, true)
 {
     m_args = args;
 
@@ -942,6 +1093,12 @@
     SetQualifiedName(m_importName + gen);
 }
 
+const vector<Type*>&
+GenericType::GenericArgumentTypes() const
+{
+    return m_args;
+}
+
 string
 GenericType::GenericArguments() const
 {
@@ -1041,10 +1198,65 @@
     }
 }
 
+void
+GenericListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    Type* generic = GenericArgumentTypes()[0];
+    if (generic == RPC_DATA_TYPE) {
+        addTo->Add(new MethodCall(data, "putRpcDataList", 2, k, v));
+    } else if (generic->RpcCreatorName() != "") {
+        addTo->Add(new MethodCall(data, "putFlattenableList", 2, k, v));
+    } else {
+        addTo->Add(new MethodCall(data, "putList", 2, k, v));
+    }
+}
+
+void
+GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, Variable** cl)
+{
+    Type* generic = GenericArgumentTypes()[0];
+    if (generic == RPC_DATA_TYPE) {
+        addTo->Add(new Assignment(v, new MethodCall(data, "getRpcDataList", 2, k)));
+    } else if (generic->RpcCreatorName() != "") {
+        addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenableList", 2, k, 
+                        new LiteralExpression(generic->RpcCreatorName()))));
+    } else {
+        string classArg = GenericArgumentTypes()[0]->QualifiedName();
+        classArg += ".class";
+        addTo->Add(new Assignment(v, new MethodCall(data, "getList", 2, k,
+                        new LiteralExpression(classArg))));
+    }
+}
+
+
+// ================================================================
+
+RpcDataType::RpcDataType()
+    :UserDataType("com.android.athome.rpc", "RpcData", true, true, true)
+{
+}
+
+void
+RpcDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data, int flags)
+{
+    addTo->Add(new MethodCall(data, "putRpcData", 2, k, v));
+}
+
+void
+RpcDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
+        Variable** cl)
+{
+    addTo->Add(new Assignment(v, new MethodCall(data, "getRpcData", 1, k)));
+}
+
+
 // ================================================================
 
 ClassLoaderType::ClassLoaderType()
-    :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
+    :Type("java.lang", "ClassLoader", BUILT_IN, false, false, false)
 {
 }
 
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index 662e3a2..ae12720 100755
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -13,7 +13,7 @@
     // kinds
     enum {
         BUILT_IN,
-        PARCELABLE,
+        USERDATA,
         INTERFACE,
         GENERATED
     };
@@ -24,9 +24,9 @@
     };
 
                     Type(const string& name, int kind, bool canWriteToParcel,
-                            bool canBeOut);
+                            bool canWriteToRpcData, bool canBeOut);
                     Type(const string& package, const string& name,
-                            int kind, bool canWriteToParcel, bool canBeOut,
+                            int kind, bool canWriteToParcel, bool canWriteToRpcData, bool canBeOut,
                             const string& declFile = "", int declLine = -1);
     virtual         ~Type();
 
@@ -36,11 +36,13 @@
     inline int      Kind() const                { return m_kind; }
     inline string   DeclFile() const            { return m_declFile; }
     inline int      DeclLine() const            { return m_declLine; }
-    inline bool     CanBeMarshalled() const     { return m_canWriteToParcel; }
+    inline bool     CanWriteToParcel() const    { return m_canWriteToParcel; }
+    inline bool     CanWriteToRpcData() const   { return m_canWriteToRpcData; }
     inline bool     CanBeOutParameter() const   { return m_canBeOut; }
     
     virtual string  ImportType() const;
     virtual string  CreatorName() const;
+    virtual string  RpcCreatorName() const;
     virtual string  InstantiableName() const;
 
     virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
@@ -59,6 +61,11 @@
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
 
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+
 protected:
     void SetQualifiedName(const string& qualified);
     Expression* BuildWriteToParcelFlags(int flags);
@@ -74,17 +81,24 @@
     int m_declLine;
     int m_kind;
     bool m_canWriteToParcel;
+    bool m_canWriteToRpcData;
     bool m_canBeOut;
 };
 
 class BasicType : public Type
 {
 public:
-                    BasicType(const string& name, const string& marshallMethod,
-                              const string& unmarshallMethod,
-                              const string& writeArray,
-                              const string& createArray,
-                              const string& readArray);
+                    BasicType(const string& name,
+                              const string& marshallParcel,
+                              const string& unmarshallParcel,
+                              const string& writeArrayParcel,
+                              const string& createArrayParcel,
+                              const string& readArrayParcel,
+                              const string& marshallRpc,
+                              const string& unmarshallRpc,
+                              const string& writeArrayRpc,
+                              const string& createArrayRpc,
+                              const string& readArrayRpc);
 
     virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, int flags);
@@ -100,12 +114,22 @@
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
 
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+
 private:
-    string m_marshallMethod;
-    string m_unmarshallMethod;
-    string m_writeArrayMethod;
-    string m_createArrayMethod;
-    string m_readArrayMethod;
+    string m_marshallParcel;
+    string m_unmarshallParcel;
+    string m_writeArrayParcel;
+    string m_createArrayParcel;
+    string m_readArrayParcel;
+    string m_marshallRpc;
+    string m_unmarshallRpc;
+    string m_writeArrayRpc;
+    string m_createArrayRpc;
+    string m_readArrayRpc;
 };
 
 class BooleanType : public Type
@@ -126,6 +150,11 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
 };
 
 class CharType : public Type
@@ -146,6 +175,11 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
 };
 
 
@@ -169,6 +203,11 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
 };
 
 class CharSequenceType : public Type
@@ -305,15 +344,22 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
 };
 
-class ParcelableType : public Type
+class UserDataType : public Type
 {
 public:
-                    ParcelableType(const string& package, const string& name,
-                            bool builtIn, const string& declFile, int declLine);
+                    UserDataType(const string& package, const string& name,
+                            bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+                            const string& declFile = "", int declLine = -1);
 
     virtual string  CreatorName() const;
+    virtual string  RpcCreatorName() const;
 
     virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, int flags);
@@ -330,6 +376,11 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
 };
 
 class InterfaceType : public Type
@@ -357,6 +408,7 @@
                     GenericType(const string& package, const string& name,
                                  const vector<Type*>& args);
 
+    const vector<Type*>& GenericArgumentTypes() const;
     string          GenericArguments() const;
 
     virtual string  ImportType() const;
@@ -374,6 +426,22 @@
     vector<Type*> m_args;
 };
 
+class RpcDataType : public UserDataType
+{
+public:
+                    RpcDataType();
+
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+};
+
+class ClassLoaderType : public Type
+{
+public:
+                    ClassLoaderType();
+};
 
 class GenericListType : public GenericType
 {
@@ -391,16 +459,15 @@
     virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
 
+    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, int flags);
+    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
+                                    Variable* data, Variable** cl);
+    
 private:
     string m_creator;
 };
 
-class ClassLoaderType : public Type
-{
-public:
-                    ClassLoaderType();
-};
-
 class Namespace
 {
 public:
@@ -438,11 +505,13 @@
 
 extern Type* VOID_TYPE;
 extern Type* BOOLEAN_TYPE;
+extern Type* BYTE_TYPE;
 extern Type* CHAR_TYPE;
 extern Type* INT_TYPE;
 extern Type* LONG_TYPE;
 extern Type* FLOAT_TYPE;
 extern Type* DOUBLE_TYPE;
+extern Type* OBJECT_TYPE;
 extern Type* STRING_TYPE;
 extern Type* CHAR_SEQUENCE_TYPE;
 extern Type* TEXT_UTILS_TYPE;
@@ -455,6 +524,13 @@
 extern Type* PARCEL_TYPE;
 extern Type* PARCELABLE_INTERFACE_TYPE;
 
+extern Type* CONTEXT_TYPE;
+
+extern Type* RPC_DATA_TYPE;
+extern Type* RPC_ERROR_TYPE;
+extern Type* RPC_CONTEXT_TYPE;
+extern Type* EVENT_FAKE_TYPE;
+
 extern Expression* NULL_VALUE;
 extern Expression* THIS_VALUE;
 extern Expression* SUPER_VALUE;
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index fb4067a..8dbbf50 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -29,7 +29,7 @@
 test_document(document_item_type* d)
 {
     while (d) {
-        if (d->item_type == INTERFACE_TYPE) {
+        if (d->item_type == INTERFACE_TYPE_BINDER) {
             interface_type* c = (interface_type*)d;
             printf("interface %s %s {\n", c->package, c->name.data);
             interface_item_type *q = (interface_item_type*)c->interface_items;
@@ -50,9 +50,14 @@
             }
             printf("}\n");
         }
-        else if (d->item_type == PARCELABLE_TYPE) {
-            parcelable_type* b = (parcelable_type*)d;
-            printf("parcelable %s %s;\n", b->package, b->name.data);
+        else if (d->item_type == USER_DATA_TYPE) {
+            user_data_type* b = (user_data_type*)d;
+            if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
+                printf("parcelable %s %s;\n", b->package, b->name.data);
+            }
+            if ((b->flattening_methods & RPC_DATA) != 0) {
+                printf("flattenable %s %s;\n", b->package, b->name.data);
+            }
         }
         else {
             printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
@@ -238,11 +243,12 @@
 {
     int err = 0;
     while (items) {
-        if (items->item_type == PARCELABLE_TYPE) {
-            parcelable_type* p = (parcelable_type*)items;
+        if (items->item_type == USER_DATA_TYPE) {
+            user_data_type* p = (user_data_type*)items;
             err |= check_filename(filename, p->package, &p->name);
         }
-        else if (items->item_type == INTERFACE_TYPE) {
+        else if (items->item_type == INTERFACE_TYPE_BINDER
+                || items->item_type == INTERFACE_TYPE_RPC) {
             interface_type* c = (interface_type*)items;
             err |= check_filename(filename, c->package, &c->name);
         }
@@ -264,8 +270,8 @@
     {
         case Type::INTERFACE:
             return "an interface";
-        case Type::PARCELABLE:
-            return "a parcelable";
+        case Type::USERDATA:
+            return "a user data";
         default:
             return "ERROR";
     }
@@ -290,12 +296,14 @@
     int err = 0;
     while (items) {
         Type* type;
-        if (items->item_type == PARCELABLE_TYPE) {
-            parcelable_type* p = (parcelable_type*)items;
-            type = new ParcelableType(p->package ? p->package : "",
-                            p->name.data, false, filename, p->name.lineno);
+        if (items->item_type == USER_DATA_TYPE) {
+            user_data_type* p = (user_data_type*)items;
+            type = new UserDataType(p->package ? p->package : "", p->name.data,
+                    false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
+                    ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
         }
-        else if (items->item_type == INTERFACE_TYPE) {
+        else if (items->item_type == INTERFACE_TYPE_BINDER
+                || items->item_type == INTERFACE_TYPE_RPC) {
             interface_type* c = (interface_type*)items;
             type = new InterfaceType(c->package ? c->package : "",
                             c->name.data, false, c->oneway,
@@ -310,7 +318,7 @@
         if (old == NULL) {
             NAMES.Add(type);
 
-            if (items->item_type == INTERFACE_TYPE) {
+            if (items->item_type == INTERFACE_TYPE_BINDER) {
                 // for interfaces, also add the stub and proxy types, we don't
                 // bother checking these for duplicates, because the parser
                 // won't let us do it.
@@ -319,17 +327,30 @@
                 string name = c->name.data;
                 name += ".Stub";
                 Type* stub = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false,
+                                        name, Type::GENERATED, false, false, false,
                                         filename, c->name.lineno);
                 NAMES.Add(stub);
 
                 name = c->name.data;
                 name += ".Stub.Proxy";
                 Type* proxy = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false,
+                                        name, Type::GENERATED, false, false, false,
                                         filename, c->name.lineno);
                 NAMES.Add(proxy);
             }
+            else if (items->item_type == INTERFACE_TYPE_RPC) {
+                // for interfaces, also add the service base type, we don't
+                // bother checking these for duplicates, because the parser
+                // won't let us do it.
+                interface_type* c = (interface_type*)items;
+
+                string name = c->name.data;
+                name += ".ServiceBase";
+                Type* base = new Type(c->package ? c->package : "",
+                                        name, Type::GENERATED, false, false, false,
+                                        filename, c->name.lineno);
+                NAMES.Add(base);
+            }
         } else {
             if (old->Kind() == Type::BUILT_IN) {
                 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
@@ -381,7 +402,7 @@
 }
 
 static int
-check_method(const char* filename, method_type* m)
+check_method(const char* filename, int kind, method_type* m)
 {
     int err = 0;
 
@@ -394,10 +415,19 @@
         return err;
     }
 
-    if (!returnType->CanBeMarshalled()) {
-        fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
-                    m->type.type.lineno, m->type.type.data);
-        err = 1;
+    if (returnType == EVENT_FAKE_TYPE) {
+        if (kind != INTERFACE_TYPE_RPC) {
+            fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
+                    filename, m->type.type.lineno);
+            err = 1;
+        }
+    } else {
+        if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
+                    : returnType->CanWriteToRpcData())) {
+            fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
+                        m->type.type.lineno, m->type.type.data);
+            err = 1;
+        }
     }
 
     if (m->type.dimension > 0 && !returnType->CanBeArray()) {
@@ -429,14 +459,31 @@
             err = 1;
             goto next;
         }
+
+        if (t == EVENT_FAKE_TYPE) {
+            fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
+                    filename, m->type.type.lineno, arg->name.data, index,
+                    arg->type.type.data);
+            err = 1;
+            goto next;
+        }
         
-        if (!t->CanBeMarshalled()) {
+        if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
             fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
                         filename, m->type.type.lineno, index,
                         arg->type.type.data, arg->name.data);
             err = 1;
         }
 
+        if (returnType == EVENT_FAKE_TYPE
+                && convert_direction(arg->direction.data) != IN_PARAMETER) {
+            fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
+                    filename, m->type.type.lineno, index,
+                    arg->type.type.data, arg->name.data);
+            err = 1;
+            goto next;
+        }
+
         if (arg->direction.data == NULL
                 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
             fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
@@ -479,7 +526,7 @@
         // check that the name doesn't match a keyword
         if (matches_keyword(arg->name.data)) {
             fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
-                    " Java keyword\n",
+                    " Java or aidl keyword\n",
                     filename, m->name.lineno, index, arg->name.data);
             err = 1;
         }
@@ -497,8 +544,9 @@
 {
     int err = 0;
     while (items) {
-        // (nothing to check for PARCELABLE_TYPE)
-        if (items->item_type == INTERFACE_TYPE) {
+        // (nothing to check for USER_DATA_TYPE)
+        if (items->item_type == INTERFACE_TYPE_BINDER
+                || items->item_type == INTERFACE_TYPE_RPC) {
             map<string,method_type*> methodNames;
             interface_type* c = (interface_type*)items;
 
@@ -507,7 +555,7 @@
                 if (member->item_type == METHOD_TYPE) {
                     method_type* m = (method_type*)member;
 
-                    err |= check_method(filename, m);
+                    err |= check_method(filename, items->item_type, m);
 
                     // prevent duplicate methods
                     if (methodNames.find(m->name.data) == methodNames.end()) {
@@ -544,26 +592,29 @@
     const document_item_type* next = items->next;
     if (items->next != NULL) {
         int lineno = -1;
-        if (next->item_type == INTERFACE_TYPE) {
+        if (next->item_type == INTERFACE_TYPE_BINDER) {
             lineno = ((interface_type*)next)->interface_token.lineno;
         }
-        else if (next->item_type == PARCELABLE_TYPE) {
-            lineno = ((parcelable_type*)next)->parcelable_token.lineno;
+        else if (next->item_type == INTERFACE_TYPE_RPC) {
+            lineno = ((interface_type*)next)->interface_token.lineno;
+        }
+        else if (next->item_type == USER_DATA_TYPE) {
+            lineno = ((user_data_type*)next)->keyword_token.lineno;
         }
         fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
                             filename, lineno);
         return 1;
     }
 
-    if (items->item_type == PARCELABLE_TYPE) {
+    if (items->item_type == USER_DATA_TYPE) {
         *onlyParcelable = true;
         if (options.failOnParcelable) {
             fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
-                            " parcelables,\n", filename,
-                            ((parcelable_type*)items)->parcelable_token.lineno);
-            fprintf(stderr, "%s:%d .aidl files that only declare parcelables "
-                            "don't need to go in the Makefile.\n", filename,
-                            ((parcelable_type*)items)->parcelable_token.lineno);
+                            " parcelables or flattenables,\n", filename,
+                            ((user_data_type*)items)->keyword_token.lineno);
+            fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
+                            "may not go in the Makefile.\n", filename,
+                            ((user_data_type*)items)->keyword_token.lineno);
             return 1;
         }
     } else {
@@ -598,7 +649,7 @@
         slash = "";
     }
 
-    if (items->item_type == INTERFACE_TYPE) {
+    if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
         fprintf(to, "%s: \\\n", options.outputFileName.c_str());
     } else {
         // parcelable: there's no output file.
@@ -658,12 +709,12 @@
 generate_outputFileName(const Options& options, const document_item_type* items)
 {
     // items has already been checked to have only one interface.
-    if (items->item_type == INTERFACE_TYPE) {
+    if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
         interface_type* type = (interface_type*)items;
 
         return generate_outputFileName2(options, type->name, type->package);
-    } else if (items->item_type == PARCELABLE_TYPE) {
-        parcelable_type* type = (parcelable_type*)items;
+    } else if (items->item_type == USER_DATA_TYPE) {
+        user_data_type* type = (user_data_type*)items;
         return generate_outputFileName2(options, type->name, type->package);
     }
 
@@ -734,24 +785,40 @@
         document_item_type* doc;
         
         if (0 == strcmp("parcelable", type)) {
-            parcelable_type* parcl = (parcelable_type*)malloc(
-                    sizeof(parcelable_type));
-            memset(parcl, 0, sizeof(parcelable_type));
-            parcl->document_item.item_type = PARCELABLE_TYPE;
-            parcl->parcelable_token.lineno = lineno;
-            parcl->parcelable_token.data = strdup(type);
+            user_data_type* parcl = (user_data_type*)malloc(
+                    sizeof(user_data_type));
+            memset(parcl, 0, sizeof(user_data_type));
+            parcl->document_item.item_type = USER_DATA_TYPE;
+            parcl->keyword_token.lineno = lineno;
+            parcl->keyword_token.data = strdup(type);
             parcl->package = packagename ? strdup(packagename) : NULL;
             parcl->name.lineno = lineno;
             parcl->name.data = strdup(classname);
             parcl->semicolon_token.lineno = lineno;
             parcl->semicolon_token.data = strdup(";");
+            parcl->flattening_methods = PARCELABLE_DATA;
+            doc = (document_item_type*)parcl;
+        }
+        else if (0 == strcmp("flattenable", type)) {
+            user_data_type* parcl = (user_data_type*)malloc(
+                    sizeof(user_data_type));
+            memset(parcl, 0, sizeof(user_data_type));
+            parcl->document_item.item_type = USER_DATA_TYPE;
+            parcl->keyword_token.lineno = lineno;
+            parcl->keyword_token.data = strdup(type);
+            parcl->package = packagename ? strdup(packagename) : NULL;
+            parcl->name.lineno = lineno;
+            parcl->name.data = strdup(classname);
+            parcl->semicolon_token.lineno = lineno;
+            parcl->semicolon_token.data = strdup(";");
+            parcl->flattening_methods = RPC_DATA;
             doc = (document_item_type*)parcl;
         }
         else if (0 == strcmp("interface", type)) {
             interface_type* iface = (interface_type*)malloc(
                     sizeof(interface_type));
             memset(iface, 0, sizeof(interface_type));
-            iface->document_item.item_type = INTERFACE_TYPE;
+            iface->document_item.item_type = INTERFACE_TYPE_BINDER;
             iface->interface_token.lineno = lineno;
             iface->interface_token.data = strdup(type);
             iface->package = packagename ? strdup(packagename) : NULL;
@@ -923,9 +990,14 @@
         }
         document_item_type* doc = g_document;
         string line;
-        if (doc->item_type == PARCELABLE_TYPE) {
-            line = "parcelable ";
-            parcelable_type* parcelable = (parcelable_type*)doc;
+        if (doc->item_type == USER_DATA_TYPE) {
+            user_data_type* parcelable = (user_data_type*)doc;
+            if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
+                line = "parcelable ";
+            }
+            if ((parcelable->flattening_methods & RPC_DATA) != 0) {
+                line = "flattenable ";
+            }
             if (parcelable->package) {
                 line += parcelable->package;
                 line += '.';
@@ -995,5 +1067,3 @@
     fprintf(stderr, "aidl: internal error\n");
     return 1;
 }
-
-
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index 9ca5deb..f203dbb0 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -63,8 +63,9 @@
 } method_type;
 
 enum {
-    PARCELABLE_TYPE = 12,
-    INTERFACE_TYPE
+    USER_DATA_TYPE = 12,
+    INTERFACE_TYPE_BINDER,
+    INTERFACE_TYPE_RPC
 };
 
 typedef struct document_item_type {
@@ -72,13 +73,21 @@
     struct document_item_type* next;
 } document_item_type;
 
-typedef struct parcelable_type {
+
+// for user_data_type.flattening_methods
+enum {
+    PARCELABLE_DATA = 0x1,
+    RPC_DATA = 0x2
+};
+
+typedef struct user_data_type {
     document_item_type document_item;
-    buffer_type parcelable_token;
+    buffer_type keyword_token; // only the first one
     char* package;
     buffer_type name;
     buffer_type semicolon_token;
-} parcelable_type;
+    int flattening_methods;
+} user_data_type;
 
 typedef struct interface_type {
     document_item_type document_item;
@@ -100,7 +109,7 @@
     method_type* method;
     interface_item_type* interface_item;
     interface_type* interface_obj;
-    parcelable_type* parcelable;
+    user_data_type* user_data;
     document_item_type* document_item;
 } lexer_type;
 
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
index 567b1cf..7c5290c 100644
--- a/tools/aidl/aidl_language_l.l
+++ b/tools/aidl/aidl_language_l.l
@@ -81,6 +81,8 @@
     /* keywords */
 parcelable      { SET_BUFFER(PARCELABLE); return PARCELABLE; }
 interface       { SET_BUFFER(INTERFACE); return INTERFACE; }
+flattenable     { SET_BUFFER(FLATTENABLE); return FLATTENABLE; }
+rpc             { SET_BUFFER(INTERFACE); return RPC; }
 in              { SET_BUFFER(IN); return IN; }
 out             { SET_BUFFER(OUT); return OUT; }
 inout           { SET_BUFFER(INOUT); return INOUT; }
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
index 3d65f17..cc04d15 100644
--- a/tools/aidl/aidl_language_y.y
+++ b/tools/aidl/aidl_language_y.y
@@ -19,6 +19,8 @@
 %token ARRAY
 %token PARCELABLE
 %token INTERFACE
+%token FLATTENABLE
+%token RPC
 %token IN
 %token OUT
 %token INOUT
@@ -72,36 +74,61 @@
     ;
 
 declaration:
-        parcelable_decl                            { $$.document_item = (document_item_type*)$1.parcelable; }
+        parcelable_decl                            { $$.document_item = (document_item_type*)$1.user_data; }
     |   interface_decl                             { $$.document_item = (document_item_type*)$1.interface_item; }
     ;
 
 parcelable_decl:
-        PARCELABLE IDENTIFIER ';'                  { 
-                                                        parcelable_type* b = (parcelable_type*)malloc(sizeof(parcelable_type));
-                                                        b->document_item.item_type = PARCELABLE_TYPE;
+        PARCELABLE IDENTIFIER ';'                   {
+                                                        user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+                                                        b->document_item.item_type = USER_DATA_TYPE;
                                                         b->document_item.next = NULL;
-                                                        b->parcelable_token = $1.buffer;
+                                                        b->keyword_token = $1.buffer;
                                                         b->name = $2.buffer;
                                                         b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
                                                         b->semicolon_token = $3.buffer;
-                                                        $$.parcelable = b;
+                                                        b->flattening_methods = PARCELABLE_DATA;
+                                                        $$.user_data = b;
                                                     }
     |   PARCELABLE ';'                              {
                                                         fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
                                                                      g_currentFilename, $1.buffer.lineno);
-                                                        $$.parcelable = NULL;
+                                                        $$.user_data = NULL;
                                                     }
     |   PARCELABLE error ';'                        {
                                                         fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n",
                                                                      g_currentFilename, $2.buffer.lineno, $2.buffer.data);
-                                                        $$.parcelable = NULL;
+                                                        $$.user_data = NULL;
                                                     }
+    |   FLATTENABLE IDENTIFIER ';'                  {
+                                                        user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
+                                                        b->document_item.item_type = USER_DATA_TYPE;
+                                                        b->document_item.next = NULL;
+                                                        b->keyword_token = $1.buffer;
+                                                        b->name = $2.buffer;
+                                                        b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
+                                                        b->semicolon_token = $3.buffer;
+                                                        b->flattening_methods = PARCELABLE_DATA | RPC_DATA;
+                                                        $$.user_data = b;
+                                                    }
+    |   FLATTENABLE ';'                             {
+                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name.\n",
+                                                                     g_currentFilename, $1.buffer.lineno);
+                                                        $$.user_data = NULL;
+                                                    }
+    |   FLATTENABLE error ';'                       {
+                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name, saw \"%s\".\n",
+                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
+                                                        $$.user_data = NULL;
+                                                    }
+
     ;
 
 interface_header:
         INTERFACE                                  {
                                                         interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+                                                        c->document_item.item_type = INTERFACE_TYPE_BINDER;
+                                                        c->document_item.next = NULL;
                                                         c->interface_token = $1.buffer;
                                                         c->oneway = false;
                                                         memset(&c->oneway_token, 0, sizeof(buffer_type));
@@ -110,19 +137,34 @@
                                                    }
     |   ONEWAY INTERFACE                           {
                                                         interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+                                                        c->document_item.item_type = INTERFACE_TYPE_BINDER;
+                                                        c->document_item.next = NULL;
                                                         c->interface_token = $2.buffer;
                                                         c->oneway = true;
                                                         c->oneway_token = $1.buffer;
                                                         c->comments_token = &c->oneway_token;
                                                         $$.interface_obj = c;
                                                    }
+    |   RPC                                        {
+                                                        interface_type* c = (interface_type*)malloc(sizeof(interface_type));
+                                                        c->document_item.item_type = INTERFACE_TYPE_RPC;
+                                                        c->document_item.next = NULL;
+                                                        c->interface_token = $1.buffer;
+                                                        c->oneway = false;
+                                                        memset(&c->oneway_token, 0, sizeof(buffer_type));
+                                                        c->comments_token = &c->interface_token;
+                                                        $$.interface_obj = c;
+                                                   }
+    ;
+
+interface_keywords:
+        INTERFACE
+    |   RPC
     ;
 
 interface_decl:
         interface_header IDENTIFIER '{' interface_items '}' { 
                                                         interface_type* c = $1.interface_obj;
-                                                        c->document_item.item_type = INTERFACE_TYPE;
-                                                        c->document_item.next = NULL;
                                                         c->name = $2.buffer;
                                                         c->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
                                                         c->open_brace_token = $3.buffer;
@@ -130,12 +172,12 @@
                                                         c->close_brace_token = $5.buffer;
                                                         $$.interface_obj = c;
                                                     }
-    |   INTERFACE error '{' interface_items '}'     {
+    |   interface_keywords error '{' interface_items '}'     {
                                                         fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected type name, saw \"%s\"\n",
                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
                                                         $$.document_item = NULL;
                                                     }
-    |   INTERFACE error '}'                             {
+    |   interface_keywords error '}'                {
                                                         fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected type name, saw \"%s\"\n",
                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
                                                         $$.document_item = NULL;
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index 83e3bbc..9e57407 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -1,5 +1,4 @@
 #include "generate_java.h"
-#include "AST.h"
 #include "Type.h"
 #include <string.h>
 #include <stdio.h>
@@ -7,18 +6,6 @@
 #include <string.h>
 
 // =================================================
-class VariableFactory
-{
-public:
-    VariableFactory(const string& base); // base must be short
-    Variable* Get(Type* type);
-    Variable* Get(int index);
-private:
-    vector<Variable*> m_vars;
-    string m_base;
-    int m_index;
-};
-
 VariableFactory::VariableFactory(const string& base)
     :m_base(base),
      m_index(0)
@@ -43,195 +30,7 @@
 }
 
 // =================================================
-class StubClass : public Class
-{
-public:
-    StubClass(Type* type, Type* interfaceType);
-    virtual ~StubClass();
-
-    Variable* transact_code;
-    Variable* transact_data;
-    Variable* transact_reply;
-    Variable* transact_flags;
-    SwitchStatement* transact_switch;
-private:
-    void make_as_interface(Type* interfaceType);
-};
-
-StubClass::StubClass(Type* type, Type* interfaceType)
-    :Class()
-{
-    this->comment = "/** Local-side IPC implementation stub class. */";
-    this->modifiers = PUBLIC | ABSTRACT | STATIC;
-    this->what = Class::CLASS;
-    this->type = type;
-    this->extends = BINDER_NATIVE_TYPE;
-    this->interfaces.push_back(interfaceType);
-
-    // descriptor
-    Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
-                            new Variable(STRING_TYPE, "DESCRIPTOR"));
-    descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
-    this->elements.push_back(descriptor);
-
-    // ctor
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->comment = "/** Construct the stub at attach it to the "
-                        "interface. */";
-        ctor->name = "Stub";
-        ctor->statements = new StatementBlock;
-    MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
-                            2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
-    ctor->statements->Add(attach);
-    this->elements.push_back(ctor);
-
-    // asInterface
-    make_as_interface(interfaceType);
-
-    // asBinder
-    Method* asBinder = new Method;
-        asBinder->modifiers = PUBLIC;
-        asBinder->returnType = IBINDER_TYPE;
-        asBinder->name = "asBinder";
-        asBinder->statements = new StatementBlock;
-    asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
-    this->elements.push_back(asBinder);
-
-    // onTransact
-    this->transact_code = new Variable(INT_TYPE, "code");
-    this->transact_data = new Variable(PARCEL_TYPE, "data");
-    this->transact_reply = new Variable(PARCEL_TYPE, "reply");
-    this->transact_flags = new Variable(INT_TYPE, "flags");
-    Method* onTransact = new Method;
-        onTransact->modifiers = PUBLIC | OVERRIDE;
-        onTransact->returnType = BOOLEAN_TYPE;
-        onTransact->name = "onTransact";
-        onTransact->parameters.push_back(this->transact_code);
-        onTransact->parameters.push_back(this->transact_data);
-        onTransact->parameters.push_back(this->transact_reply);
-        onTransact->parameters.push_back(this->transact_flags);
-        onTransact->statements = new StatementBlock;
-        onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-    this->elements.push_back(onTransact);
-    this->transact_switch = new SwitchStatement(this->transact_code);
-
-    onTransact->statements->Add(this->transact_switch);
-    MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
-                                    this->transact_code, this->transact_data,
-                                    this->transact_reply, this->transact_flags);
-    onTransact->statements->Add(new ReturnStatement(superCall));
-}
-
-StubClass::~StubClass()
-{
-}
-
-void
-StubClass::make_as_interface(Type *interfaceType)
-{
-    Variable* obj = new Variable(IBINDER_TYPE, "obj");
-
-    Method* m = new Method;
-        m->comment = "/**\n * Cast an IBinder object into an ";
-        m->comment += interfaceType->QualifiedName();
-        m->comment += " interface,\n";
-        m->comment += " * generating a proxy if needed.\n */";
-        m->modifiers = PUBLIC | STATIC;
-        m->returnType = interfaceType;
-        m->name = "asInterface";
-        m->parameters.push_back(obj);
-        m->statements = new StatementBlock;
-
-    IfStatement* ifstatement = new IfStatement();
-        ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
-        ifstatement->statements = new StatementBlock;
-        ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
-    m->statements->Add(ifstatement);
-
-    // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
-    MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
-    queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
-    IInterfaceType* iinType = new IInterfaceType();
-    Variable *iin = new Variable(iinType, "iin");
-    VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType);
-    m->statements->Add(iinVd);
-
-    // Ensure the instance type of the local object is as expected.
-    // One scenario where this is needed is if another package (with a
-    // different class loader) runs in the same process as the service.
-
-    // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
-    Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
-    Comparison* instOfCheck = new Comparison(iin, " instanceof ",
-            new LiteralExpression(interfaceType->QualifiedName()));
-    IfStatement* instOfStatement = new IfStatement();
-        instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
-        instOfStatement->statements = new StatementBlock;
-        instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
-    m->statements->Add(instOfStatement);
-
-    string proxyType = interfaceType->QualifiedName();
-    proxyType += ".Stub.Proxy";
-    NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
-    ne->arguments.push_back(obj);
-    m->statements->Add(new ReturnStatement(ne));
-
-    this->elements.push_back(m);
-}
-
-
-
-// =================================================
-class ProxyClass : public Class
-{
-public:
-    ProxyClass(Type* type, InterfaceType* interfaceType);
-    virtual ~ProxyClass();
-
-    Variable* mRemote;
-    bool mOneWay;
-};
-
-ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
-    :Class()
-{
-    this->modifiers = PRIVATE | STATIC;
-    this->what = Class::CLASS;
-    this->type = type;
-    this->interfaces.push_back(interfaceType);
-
-    mOneWay = interfaceType->OneWay();
-
-    // IBinder mRemote
-    mRemote = new Variable(IBINDER_TYPE, "mRemote");
-    this->elements.push_back(new Field(PRIVATE, mRemote));
-
-    // Proxy()
-    Variable* remote = new Variable(IBINDER_TYPE, "remote");
-    Method* ctor = new Method;
-        ctor->name = "Proxy";
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(remote);
-    ctor->statements->Add(new Assignment(mRemote, remote));
-    this->elements.push_back(ctor);
-
-    // IBinder asBinder()
-    Method* asBinder = new Method;
-        asBinder->modifiers = PUBLIC;
-        asBinder->returnType = IBINDER_TYPE;
-        asBinder->name = "asBinder";
-        asBinder->statements = new StatementBlock;
-    asBinder->statements->Add(new ReturnStatement(mRemote));
-    this->elements.push_back(asBinder);
-}
-
-ProxyClass::~ProxyClass()
-{
-}
-
-// =================================================
-static string
+string
 gather_comments(extra_text_type* extra)
 {
     string s;
@@ -249,7 +48,7 @@
     return s;
 }
 
-static string
+string
 append(const char* a, const char* b)
 {
     string s = a;
@@ -257,379 +56,25 @@
     return s;
 }
 
-static void
-generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
-                            Variable* parcel)
-{
-    Variable* len = new Variable(INT_TYPE, v->name + "_length");
-    addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
-    IfStatement* lencheck = new IfStatement();
-    lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
-    lencheck->statements->Add(new Assignment(v, NULL_VALUE));
-    lencheck->elseif = new IfStatement();
-    lencheck->elseif->statements->Add(new Assignment(v,
-                new NewArrayExpression(t, len)));
-    addTo->Add(lencheck);
-}
-
-static void
-generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
-                            Variable* parcel, int flags)
-{
-    if (v->dimension == 0) {
-        t->WriteToParcel(addTo, v, parcel, flags);
-    }
-    if (v->dimension == 1) {
-        t->WriteArrayToParcel(addTo, v, parcel, flags);
-    }
-}
-
-static void
-generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable** cl)
-{
-    if (v->dimension == 0) {
-        t->CreateFromParcel(addTo, v, parcel, cl);
-    }
-    if (v->dimension == 1) {
-        t->CreateArrayFromParcel(addTo, v, parcel, cl);
-    }
-}
-
-static void
-generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable** cl)
-{
-    if (v->dimension == 0) {
-        t->ReadFromParcel(addTo, v, parcel, cl);
-    }
-    if (v->dimension == 1) {
-        t->ReadArrayFromParcel(addTo, v, parcel, cl);
-    }
-}
-
-
-static void
-generate_method(const method_type* method, Class* interface,
-                    StubClass* stubClass, ProxyClass* proxyClass, int index)
-{
-    arg_type* arg;
-    int i;
-    bool hasOutParams = false;
-
-    const bool oneway = proxyClass->mOneWay || method->oneway;
-
-    // == the TRANSACT_ constant =============================================
-    string transactCodeName = "TRANSACTION_";
-    transactCodeName += method->name.data;
-
-    char transactCodeValue[50];
-    sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
-
-    Field* transactCode = new Field(STATIC | FINAL,
-                            new Variable(INT_TYPE, transactCodeName));
-    transactCode->value = transactCodeValue;
-    stubClass->elements.push_back(transactCode);
-
-    // == the declaration in the interface ===================================
-    Method* decl = new Method;
-        decl->comment = gather_comments(method->comments_token->extra);
-        decl->modifiers = PUBLIC;
-        decl->returnType = NAMES.Search(method->type.type.data);
-        decl->returnTypeDimension = method->type.dimension;
-        decl->name = method->name.data;
-
-    arg = method->args;
-    while (arg != NULL) {
-        decl->parameters.push_back(new Variable(
-                            NAMES.Search(arg->type.type.data), arg->name.data,
-                            arg->type.dimension));
-        arg = arg->next;
-    }
-
-    decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-
-    interface->elements.push_back(decl);
-
-    // == the stub method ====================================================
-
-    Case* c = new Case(transactCodeName);
-
-    MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
-
-    // interface token validation is the very first thing we do
-    c->statements->Add(new MethodCall(stubClass->transact_data,
-            "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
-
-    // args
-    Variable* cl = NULL;
-    VariableFactory stubArgs("_arg");
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = stubArgs.Get(t);
-        v->dimension = arg->type.dimension;
-
-        c->statements->Add(new VariableDeclaration(v));
-
-        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
-            generate_create_from_parcel(t, c->statements, v,
-                    stubClass->transact_data, &cl);
-        } else {
-            if (arg->type.dimension == 0) {
-                c->statements->Add(new Assignment(
-                                                v, new NewExpression(v->type)));
-            }
-            else if (arg->type.dimension == 1) {
-                generate_new_array(v->type, c->statements, v,
-                        stubClass->transact_data);
-            }
-            else {
-                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
-                        __LINE__);
-            }
-        }
-
-        realCall->arguments.push_back(v);
-
-        arg = arg->next;
-    }
-
-    // the real call
-    Variable* _result = NULL;
-    if (0 == strcmp(method->type.type.data, "void")) {
-        c->statements->Add(realCall);
-
-        if (!oneway) {
-            // report that there were no exceptions
-            MethodCall* ex = new MethodCall(stubClass->transact_reply,
-                    "writeNoException", 0);
-            c->statements->Add(ex);
-        }
-    } else {
-        _result = new Variable(decl->returnType, "_result",
-                                decl->returnTypeDimension);
-        c->statements->Add(new VariableDeclaration(_result, realCall));
-
-        if (!oneway) {
-            // report that there were no exceptions
-            MethodCall* ex = new MethodCall(stubClass->transact_reply,
-                    "writeNoException", 0);
-            c->statements->Add(ex);
-        }
-
-        // marshall the return value
-        generate_write_to_parcel(decl->returnType, c->statements, _result,
-                                    stubClass->transact_reply,
-                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
-    }
-
-    // out parameters
-    i = 0;
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = stubArgs.Get(i++);
-
-        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-            generate_write_to_parcel(t, c->statements, v,
-                                stubClass->transact_reply,
-                                Type::PARCELABLE_WRITE_RETURN_VALUE);
-            hasOutParams = true;
-        }
-
-        arg = arg->next;
-    }
-
-    // return true
-    c->statements->Add(new ReturnStatement(TRUE_VALUE));
-    stubClass->transact_switch->cases.push_back(c);
-
-    // == the proxy method ===================================================
-    Method* proxy = new Method;
-        proxy->comment = gather_comments(method->comments_token->extra);
-        proxy->modifiers = PUBLIC;
-        proxy->returnType = NAMES.Search(method->type.type.data);
-        proxy->returnTypeDimension = method->type.dimension;
-        proxy->name = method->name.data;
-        proxy->statements = new StatementBlock;
-        arg = method->args;
-        while (arg != NULL) {
-            proxy->parameters.push_back(new Variable(
-                            NAMES.Search(arg->type.type.data), arg->name.data,
-                            arg->type.dimension));
-            arg = arg->next;
-        }
-        proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-    proxyClass->elements.push_back(proxy);
-
-    // the parcels
-    Variable* _data = new Variable(PARCEL_TYPE, "_data");
-    proxy->statements->Add(new VariableDeclaration(_data,
-                                new MethodCall(PARCEL_TYPE, "obtain")));
-    Variable* _reply = NULL;
-    if (!oneway) {
-        _reply = new Variable(PARCEL_TYPE, "_reply");
-        proxy->statements->Add(new VariableDeclaration(_reply,
-                                    new MethodCall(PARCEL_TYPE, "obtain")));
-    }
-
-    // the return value
-    _result = NULL;
-    if (0 != strcmp(method->type.type.data, "void")) {
-        _result = new Variable(proxy->returnType, "_result",
-                method->type.dimension);
-        proxy->statements->Add(new VariableDeclaration(_result));
-    }
-
-    // try and finally
-    TryStatement* tryStatement = new TryStatement();
-    proxy->statements->Add(tryStatement);
-    FinallyStatement* finallyStatement = new FinallyStatement();
-    proxy->statements->Add(finallyStatement);
-
-    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
-    tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
-            1, new LiteralExpression("DESCRIPTOR")));
-
-    // the parameters
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
-        int dir = convert_direction(arg->direction.data);
-        if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
-            IfStatement* checklen = new IfStatement();
-            checklen->expression = new Comparison(v, "==", NULL_VALUE);
-            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
-                        new LiteralExpression("-1")));
-            checklen->elseif = new IfStatement();
-            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
-                        1, new FieldVariable(v, "length")));
-            tryStatement->statements->Add(checklen);
-        }
-        else if (dir & IN_PARAMETER) {
-            generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
-        }
-        arg = arg->next;
-    }
-
-    // the transact call
-    MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
-                            new LiteralExpression("Stub." + transactCodeName),
-                            _data, _reply ? _reply : NULL_VALUE,
-                            new LiteralExpression(
-                                oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
-    tryStatement->statements->Add(call);
-
-    // throw back exceptions.
-    if (_reply) {
-        MethodCall* ex = new MethodCall(_reply, "readException", 0);
-        tryStatement->statements->Add(ex);
-    }
-
-    // returning and cleanup
-    if (_reply != NULL) {
-        if (_result != NULL) {
-            generate_create_from_parcel(proxy->returnType,
-                    tryStatement->statements, _result, _reply, &cl);
-        }
-
-        // the out/inout parameters
-        arg = method->args;
-        while (arg != NULL) {
-            Type* t = NAMES.Search(arg->type.type.data);
-            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
-            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-                generate_read_from_parcel(t, tryStatement->statements,
-                                            v, _reply, &cl);
-            }
-            arg = arg->next;
-        }
-
-        finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
-    }
-    finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
-
-    if (_result != NULL) {
-        proxy->statements->Add(new ReturnStatement(_result));
-    }
-}
-
-static void
-generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
-{
-    // the interface descriptor transaction handler
-    Case* c = new Case("INTERFACE_TRANSACTION");
-    c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
-            1, new LiteralExpression("DESCRIPTOR")));
-    c->statements->Add(new ReturnStatement(TRUE_VALUE));
-    stub->transact_switch->cases.push_back(c);
-
-    // and the proxy-side method returning the descriptor directly
-    Method* getDesc = new Method;
-    getDesc->modifiers = PUBLIC;
-    getDesc->returnType = STRING_TYPE;
-    getDesc->returnTypeDimension = 0;
-    getDesc->name = "getInterfaceDescriptor";
-    getDesc->statements = new StatementBlock;
-    getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
-    proxy->elements.push_back(getDesc);
-}
-
-static Class*
-generate_interface_class(const interface_type* iface)
-{
-    InterfaceType* interfaceType = static_cast<InterfaceType*>(
-        NAMES.Find(iface->package, iface->name.data));
-
-    // the interface class
-    Class* interface = new Class;
-        interface->comment = gather_comments(iface->comments_token->extra);
-        interface->modifiers = PUBLIC;
-        interface->what = Class::INTERFACE;
-        interface->type = interfaceType;
-        interface->interfaces.push_back(IINTERFACE_TYPE);
-
-    // the stub inner class
-    StubClass* stub = new StubClass(
-        NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
-        interfaceType);
-    interface->elements.push_back(stub);
-
-    // the proxy inner class
-    ProxyClass* proxy = new ProxyClass(
-        NAMES.Find(iface->package,
-                         append(iface->name.data, ".Stub.Proxy").c_str()),
-        interfaceType);
-    stub->elements.push_back(proxy);
-
-    // stub and proxy support for getInterfaceDescriptor()
-    generate_interface_descriptors(stub, proxy);
-
-    // all the declared methods of the interface
-    int index = 0;
-    interface_item_type* item = iface->interface_items;
-    while (item != NULL) {
-        if (item->item_type == METHOD_TYPE) {
-            generate_method((method_type*)item, interface, stub, proxy, index);
-        }
-        item = item->next;
-        index++;
-    }
-
-    return interface;
-}
-
+// =================================================
 int
 generate_java(const string& filename, const string& originalSrc,
                 interface_type* iface)
 {
+    Class* cl;
+
+    if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
+        cl = generate_binder_interface_class(iface);
+    }
+    else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
+        cl = generate_rpc_interface_class(iface);
+    }
+
     Document* document = new Document;
         document->comment = "";
         if (iface->package) document->package = iface->package;
         document->originalSrc = originalSrc;
-        document->classes.push_back(generate_interface_class(iface));
+        document->classes.push_back(cl);
 
 //    printf("outputting... filename=%s\n", filename.c_str());
     FILE* to;
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
index 203fe23..4bfcfeb 100644
--- a/tools/aidl/generate_java.h
+++ b/tools/aidl/generate_java.h
@@ -2,6 +2,7 @@
 #define GENERATE_JAVA_H
 
 #include "aidl_language.h"
+#include "AST.h"
 
 #include <string>
 
@@ -10,5 +11,23 @@
 int generate_java(const string& filename, const string& originalSrc,
                 interface_type* iface);
 
+Class* generate_binder_interface_class(const interface_type* iface);
+Class* generate_rpc_interface_class(const interface_type* iface);
+
+string gather_comments(extra_text_type* extra);
+string append(const char* a, const char* b);
+
+class VariableFactory
+{
+public:
+    VariableFactory(const string& base); // base must be short
+    Variable* Get(Type* type);
+    Variable* Get(int index);
+private:
+    vector<Variable*> m_vars;
+    string m_base;
+    int m_index;
+};
+
 #endif // GENERATE_JAVA_H
 
diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp
new file mode 100644
index 0000000..2e459a8
--- /dev/null
+++ b/tools/aidl/generate_java_binder.cpp
@@ -0,0 +1,559 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// =================================================
+class StubClass : public Class
+{
+public:
+    StubClass(Type* type, Type* interfaceType);
+    virtual ~StubClass();
+
+    Variable* transact_code;
+    Variable* transact_data;
+    Variable* transact_reply;
+    Variable* transact_flags;
+    SwitchStatement* transact_switch;
+private:
+    void make_as_interface(Type* interfaceType);
+};
+
+StubClass::StubClass(Type* type, Type* interfaceType)
+    :Class()
+{
+    this->comment = "/** Local-side IPC implementation stub class. */";
+    this->modifiers = PUBLIC | ABSTRACT | STATIC;
+    this->what = Class::CLASS;
+    this->type = type;
+    this->extends = BINDER_NATIVE_TYPE;
+    this->interfaces.push_back(interfaceType);
+
+    // descriptor
+    Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
+                            new Variable(STRING_TYPE, "DESCRIPTOR"));
+    descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
+    this->elements.push_back(descriptor);
+
+    // ctor
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->comment = "/** Construct the stub at attach it to the "
+                        "interface. */";
+        ctor->name = "Stub";
+        ctor->statements = new StatementBlock;
+    MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
+                            2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
+    ctor->statements->Add(attach);
+    this->elements.push_back(ctor);
+
+    // asInterface
+    make_as_interface(interfaceType);
+
+    // asBinder
+    Method* asBinder = new Method;
+        asBinder->modifiers = PUBLIC;
+        asBinder->returnType = IBINDER_TYPE;
+        asBinder->name = "asBinder";
+        asBinder->statements = new StatementBlock;
+    asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
+    this->elements.push_back(asBinder);
+
+    // onTransact
+    this->transact_code = new Variable(INT_TYPE, "code");
+    this->transact_data = new Variable(PARCEL_TYPE, "data");
+    this->transact_reply = new Variable(PARCEL_TYPE, "reply");
+    this->transact_flags = new Variable(INT_TYPE, "flags");
+    Method* onTransact = new Method;
+        onTransact->modifiers = PUBLIC | OVERRIDE;
+        onTransact->returnType = BOOLEAN_TYPE;
+        onTransact->name = "onTransact";
+        onTransact->parameters.push_back(this->transact_code);
+        onTransact->parameters.push_back(this->transact_data);
+        onTransact->parameters.push_back(this->transact_reply);
+        onTransact->parameters.push_back(this->transact_flags);
+        onTransact->statements = new StatementBlock;
+        onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+    this->elements.push_back(onTransact);
+    this->transact_switch = new SwitchStatement(this->transact_code);
+
+    onTransact->statements->Add(this->transact_switch);
+    MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
+                                    this->transact_code, this->transact_data,
+                                    this->transact_reply, this->transact_flags);
+    onTransact->statements->Add(new ReturnStatement(superCall));
+}
+
+StubClass::~StubClass()
+{
+}
+
+void
+StubClass::make_as_interface(Type *interfaceType)
+{
+    Variable* obj = new Variable(IBINDER_TYPE, "obj");
+
+    Method* m = new Method;
+        m->comment = "/**\n * Cast an IBinder object into an ";
+        m->comment += interfaceType->QualifiedName();
+        m->comment += " interface,\n";
+        m->comment += " * generating a proxy if needed.\n */";
+        m->modifiers = PUBLIC | STATIC;
+        m->returnType = interfaceType;
+        m->name = "asInterface";
+        m->parameters.push_back(obj);
+        m->statements = new StatementBlock;
+
+    IfStatement* ifstatement = new IfStatement();
+        ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
+        ifstatement->statements = new StatementBlock;
+        ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
+    m->statements->Add(ifstatement);
+
+    // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
+    MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
+    queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
+    IInterfaceType* iinType = new IInterfaceType();
+    Variable *iin = new Variable(iinType, "iin");
+    VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, iinType);
+    m->statements->Add(iinVd);
+
+    // Ensure the instance type of the local object is as expected.
+    // One scenario where this is needed is if another package (with a
+    // different class loader) runs in the same process as the service.
+
+    // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
+    Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
+    Comparison* instOfCheck = new Comparison(iin, " instanceof ",
+            new LiteralExpression(interfaceType->QualifiedName()));
+    IfStatement* instOfStatement = new IfStatement();
+        instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
+        instOfStatement->statements = new StatementBlock;
+        instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
+    m->statements->Add(instOfStatement);
+
+    string proxyType = interfaceType->QualifiedName();
+    proxyType += ".Stub.Proxy";
+    NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
+    ne->arguments.push_back(obj);
+    m->statements->Add(new ReturnStatement(ne));
+
+    this->elements.push_back(m);
+}
+
+
+
+// =================================================
+class ProxyClass : public Class
+{
+public:
+    ProxyClass(Type* type, InterfaceType* interfaceType);
+    virtual ~ProxyClass();
+
+    Variable* mRemote;
+    bool mOneWay;
+};
+
+ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
+    :Class()
+{
+    this->modifiers = PRIVATE | STATIC;
+    this->what = Class::CLASS;
+    this->type = type;
+    this->interfaces.push_back(interfaceType);
+
+    mOneWay = interfaceType->OneWay();
+
+    // IBinder mRemote
+    mRemote = new Variable(IBINDER_TYPE, "mRemote");
+    this->elements.push_back(new Field(PRIVATE, mRemote));
+
+    // Proxy()
+    Variable* remote = new Variable(IBINDER_TYPE, "remote");
+    Method* ctor = new Method;
+        ctor->name = "Proxy";
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(remote);
+    ctor->statements->Add(new Assignment(mRemote, remote));
+    this->elements.push_back(ctor);
+
+    // IBinder asBinder()
+    Method* asBinder = new Method;
+        asBinder->modifiers = PUBLIC;
+        asBinder->returnType = IBINDER_TYPE;
+        asBinder->name = "asBinder";
+        asBinder->statements = new StatementBlock;
+    asBinder->statements->Add(new ReturnStatement(mRemote));
+    this->elements.push_back(asBinder);
+}
+
+ProxyClass::~ProxyClass()
+{
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
+                            Variable* parcel)
+{
+    Variable* len = new Variable(INT_TYPE, v->name + "_length");
+    addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
+    IfStatement* lencheck = new IfStatement();
+    lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
+    lencheck->statements->Add(new Assignment(v, NULL_VALUE));
+    lencheck->elseif = new IfStatement();
+    lencheck->elseif->statements->Add(new Assignment(v,
+                new NewArrayExpression(t, len)));
+    addTo->Add(lencheck);
+}
+
+static void
+generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
+                            Variable* parcel, int flags)
+{
+    if (v->dimension == 0) {
+        t->WriteToParcel(addTo, v, parcel, flags);
+    }
+    if (v->dimension == 1) {
+        t->WriteArrayToParcel(addTo, v, parcel, flags);
+    }
+}
+
+static void
+generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+                            Variable* parcel, Variable** cl)
+{
+    if (v->dimension == 0) {
+        t->CreateFromParcel(addTo, v, parcel, cl);
+    }
+    if (v->dimension == 1) {
+        t->CreateArrayFromParcel(addTo, v, parcel, cl);
+    }
+}
+
+static void
+generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
+                            Variable* parcel, Variable** cl)
+{
+    if (v->dimension == 0) {
+        t->ReadFromParcel(addTo, v, parcel, cl);
+    }
+    if (v->dimension == 1) {
+        t->ReadArrayFromParcel(addTo, v, parcel, cl);
+    }
+}
+
+
+static void
+generate_method(const method_type* method, Class* interface,
+                    StubClass* stubClass, ProxyClass* proxyClass, int index)
+{
+    arg_type* arg;
+    int i;
+    bool hasOutParams = false;
+
+    const bool oneway = proxyClass->mOneWay || method->oneway;
+
+    // == the TRANSACT_ constant =============================================
+    string transactCodeName = "TRANSACTION_";
+    transactCodeName += method->name.data;
+
+    char transactCodeValue[50];
+    sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
+
+    Field* transactCode = new Field(STATIC | FINAL,
+                            new Variable(INT_TYPE, transactCodeName));
+    transactCode->value = transactCodeValue;
+    stubClass->elements.push_back(transactCode);
+
+    // == the declaration in the interface ===================================
+    Method* decl = new Method;
+        decl->comment = gather_comments(method->comments_token->extra);
+        decl->modifiers = PUBLIC;
+        decl->returnType = NAMES.Search(method->type.type.data);
+        decl->returnTypeDimension = method->type.dimension;
+        decl->name = method->name.data;
+
+    arg = method->args;
+    while (arg != NULL) {
+        decl->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+        arg = arg->next;
+    }
+
+    decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+
+    interface->elements.push_back(decl);
+
+    // == the stub method ====================================================
+
+    Case* c = new Case(transactCodeName);
+
+    MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
+
+    // interface token validation is the very first thing we do
+    c->statements->Add(new MethodCall(stubClass->transact_data,
+            "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
+
+    // args
+    Variable* cl = NULL;
+    VariableFactory stubArgs("_arg");
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(t);
+        v->dimension = arg->type.dimension;
+
+        c->statements->Add(new VariableDeclaration(v));
+
+        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+            generate_create_from_parcel(t, c->statements, v,
+                    stubClass->transact_data, &cl);
+        } else {
+            if (arg->type.dimension == 0) {
+                c->statements->Add(new Assignment(v, new NewExpression(v->type)));
+            }
+            else if (arg->type.dimension == 1) {
+                generate_new_array(v->type, c->statements, v,
+                        stubClass->transact_data);
+            }
+            else {
+                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+                        __LINE__);
+            }
+        }
+
+        realCall->arguments.push_back(v);
+
+        arg = arg->next;
+    }
+
+    // the real call
+    Variable* _result = NULL;
+    if (0 == strcmp(method->type.type.data, "void")) {
+        c->statements->Add(realCall);
+
+        if (!oneway) {
+            // report that there were no exceptions
+            MethodCall* ex = new MethodCall(stubClass->transact_reply,
+                    "writeNoException", 0);
+            c->statements->Add(ex);
+        }
+    } else {
+        _result = new Variable(decl->returnType, "_result",
+                                decl->returnTypeDimension);
+        c->statements->Add(new VariableDeclaration(_result, realCall));
+
+        if (!oneway) {
+            // report that there were no exceptions
+            MethodCall* ex = new MethodCall(stubClass->transact_reply,
+                    "writeNoException", 0);
+            c->statements->Add(ex);
+        }
+
+        // marshall the return value
+        generate_write_to_parcel(decl->returnType, c->statements, _result,
+                                    stubClass->transact_reply,
+                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
+    }
+
+    // out parameters
+    i = 0;
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(i++);
+
+        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+            generate_write_to_parcel(t, c->statements, v,
+                                stubClass->transact_reply,
+                                Type::PARCELABLE_WRITE_RETURN_VALUE);
+            hasOutParams = true;
+        }
+
+        arg = arg->next;
+    }
+
+    // return true
+    c->statements->Add(new ReturnStatement(TRUE_VALUE));
+    stubClass->transact_switch->cases.push_back(c);
+
+    // == the proxy method ===================================================
+    Method* proxy = new Method;
+        proxy->comment = gather_comments(method->comments_token->extra);
+        proxy->modifiers = PUBLIC;
+        proxy->returnType = NAMES.Search(method->type.type.data);
+        proxy->returnTypeDimension = method->type.dimension;
+        proxy->name = method->name.data;
+        proxy->statements = new StatementBlock;
+        arg = method->args;
+        while (arg != NULL) {
+            proxy->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+            arg = arg->next;
+        }
+        proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
+    proxyClass->elements.push_back(proxy);
+
+    // the parcels
+    Variable* _data = new Variable(PARCEL_TYPE, "_data");
+    proxy->statements->Add(new VariableDeclaration(_data,
+                                new MethodCall(PARCEL_TYPE, "obtain")));
+    Variable* _reply = NULL;
+    if (!oneway) {
+        _reply = new Variable(PARCEL_TYPE, "_reply");
+        proxy->statements->Add(new VariableDeclaration(_reply,
+                                    new MethodCall(PARCEL_TYPE, "obtain")));
+    }
+
+    // the return value
+    _result = NULL;
+    if (0 != strcmp(method->type.type.data, "void")) {
+        _result = new Variable(proxy->returnType, "_result",
+                method->type.dimension);
+        proxy->statements->Add(new VariableDeclaration(_result));
+    }
+
+    // try and finally
+    TryStatement* tryStatement = new TryStatement();
+    proxy->statements->Add(tryStatement);
+    FinallyStatement* finallyStatement = new FinallyStatement();
+    proxy->statements->Add(finallyStatement);
+
+    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
+    tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
+            1, new LiteralExpression("DESCRIPTOR")));
+
+    // the parameters
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+        int dir = convert_direction(arg->direction.data);
+        if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
+            IfStatement* checklen = new IfStatement();
+            checklen->expression = new Comparison(v, "==", NULL_VALUE);
+            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
+                        new LiteralExpression("-1")));
+            checklen->elseif = new IfStatement();
+            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
+                        1, new FieldVariable(v, "length")));
+            tryStatement->statements->Add(checklen);
+        }
+        else if (dir & IN_PARAMETER) {
+            generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
+        }
+        arg = arg->next;
+    }
+
+    // the transact call
+    MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
+                            new LiteralExpression("Stub." + transactCodeName),
+                            _data, _reply ? _reply : NULL_VALUE,
+                            new LiteralExpression(
+                                oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
+    tryStatement->statements->Add(call);
+
+    // throw back exceptions.
+    if (_reply) {
+        MethodCall* ex = new MethodCall(_reply, "readException", 0);
+        tryStatement->statements->Add(ex);
+    }
+
+    // returning and cleanup
+    if (_reply != NULL) {
+        if (_result != NULL) {
+            generate_create_from_parcel(proxy->returnType,
+                    tryStatement->statements, _result, _reply, &cl);
+        }
+
+        // the out/inout parameters
+        arg = method->args;
+        while (arg != NULL) {
+            Type* t = NAMES.Search(arg->type.type.data);
+            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+                generate_read_from_parcel(t, tryStatement->statements,
+                                            v, _reply, &cl);
+            }
+            arg = arg->next;
+        }
+
+        finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
+    }
+    finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
+
+    if (_result != NULL) {
+        proxy->statements->Add(new ReturnStatement(_result));
+    }
+}
+
+static void
+generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
+{
+    // the interface descriptor transaction handler
+    Case* c = new Case("INTERFACE_TRANSACTION");
+    c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
+            1, new LiteralExpression("DESCRIPTOR")));
+    c->statements->Add(new ReturnStatement(TRUE_VALUE));
+    stub->transact_switch->cases.push_back(c);
+
+    // and the proxy-side method returning the descriptor directly
+    Method* getDesc = new Method;
+    getDesc->modifiers = PUBLIC;
+    getDesc->returnType = STRING_TYPE;
+    getDesc->returnTypeDimension = 0;
+    getDesc->name = "getInterfaceDescriptor";
+    getDesc->statements = new StatementBlock;
+    getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
+    proxy->elements.push_back(getDesc);
+}
+
+Class*
+generate_binder_interface_class(const interface_type* iface)
+{
+    InterfaceType* interfaceType = static_cast<InterfaceType*>(
+        NAMES.Find(iface->package, iface->name.data));
+
+    // the interface class
+    Class* interface = new Class;
+        interface->comment = gather_comments(iface->comments_token->extra);
+        interface->modifiers = PUBLIC;
+        interface->what = Class::INTERFACE;
+        interface->type = interfaceType;
+        interface->interfaces.push_back(IINTERFACE_TYPE);
+
+    // the stub inner class
+    StubClass* stub = new StubClass(
+        NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
+        interfaceType);
+    interface->elements.push_back(stub);
+
+    // the proxy inner class
+    ProxyClass* proxy = new ProxyClass(
+        NAMES.Find(iface->package,
+                         append(iface->name.data, ".Stub.Proxy").c_str()),
+        interfaceType);
+    stub->elements.push_back(proxy);
+
+    // stub and proxy support for getInterfaceDescriptor()
+    generate_interface_descriptors(stub, proxy);
+
+    // all the declared methods of the interface
+    int index = 0;
+    interface_item_type* item = iface->interface_items;
+    while (item != NULL) {
+        if (item->item_type == METHOD_TYPE) {
+            generate_method((method_type*)item, interface, stub, proxy, index);
+        }
+        item = item->next;
+        index++;
+    }
+
+    return interface;
+}
+
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
new file mode 100644
index 0000000..ecff3a1
--- /dev/null
+++ b/tools/aidl/generate_java_rpc.cpp
@@ -0,0 +1,998 @@
+#include "generate_java.h"
+#include "Type.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+Type* SERVICE_CONTEXT_TYPE = new Type("android.content",
+        "Context", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_BASE_TYPE = new Type("com.android.athome.connector",
+        "EventListener", Type::BUILT_IN, false, false, false);
+Type* PRESENTER_LISTENER_BASE_TYPE = new Type("com.android.athome.connector",
+        "EventListener.Listener", Type::BUILT_IN, false, false, false);
+Type* RPC_BROKER_TYPE = new Type("com.android.athome.connector", "Broker",
+        Type::BUILT_IN, false, false, false);
+Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer",
+        Type::BUILT_IN, false, false, false);
+Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo",
+        Type::BUILT_IN, false, false, false);
+// TODO: Just use Endpoint, so this works for all endpoints.
+Type* RPC_CONNECTOR_TYPE = new Type("com.android.athome.connector", "Connector",
+        Type::BUILT_IN, false, false, false);
+Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("com.android.athome.rpc",
+        "EndpointInfo", true, __FILE__, __LINE__);
+Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("com.android.athome.rpc", "RpcResultHandler",
+        true, __FILE__, __LINE__);
+Type* RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler",
+        Type::BUILT_IN, false, false, false);
+Type* RPC_CONTEXT_TYPE = new UserDataType("com.android.athome.rpc", "RpcContext", true,
+        __FILE__, __LINE__);
+
+static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
+        Variable* v, Variable* data, Variable** cl);
+static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from);
+static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v,
+        Variable* data);
+
+static string
+format_int(int n)
+{
+    char str[20];
+    sprintf(str, "%d", n);
+    return string(str);
+}
+
+static string
+class_name_leaf(const string& str)
+{
+    string::size_type pos = str.rfind('.');
+    if (pos == string::npos) {
+        return str;
+    } else {
+        return string(str, pos+1);
+    }
+}
+
+static string
+results_class_name(const string& n)
+{
+    string str = n;
+    str[0] = toupper(str[0]);
+    str.insert(0, "On");
+    return str;
+}
+
+static string
+results_method_name(const string& n)
+{
+    string str = n;
+    str[0] = toupper(str[0]);
+    str.insert(0, "on");
+    return str;
+}
+
+static string
+push_method_name(const string& n)
+{
+    string str = n;
+    str[0] = toupper(str[0]);
+    str.insert(0, "push");
+    return str;
+}
+
+// =================================================
+class DispatcherClass : public Class
+{
+public:
+    DispatcherClass(const interface_type* iface, Expression* target);
+    virtual ~DispatcherClass();
+
+    void AddMethod(const method_type* method);
+    void DoneWithMethods();
+
+    Method* processMethod;
+    Variable* actionParam;
+    Variable* requestParam;
+    Variable* rpcContextParam;
+    Variable* errorParam;
+    Variable* requestData;
+    Variable* resultData;
+    IfStatement* dispatchIfStatement;
+    Expression* targetExpression;
+
+private:
+    void generate_process();
+};
+
+DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target)
+    :Class(),
+     dispatchIfStatement(NULL),
+     targetExpression(target)
+{
+    generate_process();
+}
+
+DispatcherClass::~DispatcherClass()
+{
+}
+
+void
+DispatcherClass::generate_process()
+{
+    // byte[] process(String action, byte[] params, RpcContext context, RpcError status)
+    this->processMethod = new Method;
+        this->processMethod->modifiers = PUBLIC;
+        this->processMethod->returnType = BYTE_TYPE;
+        this->processMethod->returnTypeDimension = 1;
+        this->processMethod->name = "process";
+        this->processMethod->statements = new StatementBlock;
+
+    this->actionParam = new Variable(STRING_TYPE, "action");
+    this->processMethod->parameters.push_back(this->actionParam);
+
+    this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
+    this->processMethod->parameters.push_back(this->requestParam);
+
+    this->rpcContextParam = new Variable(RPC_CONTEXT_TYPE, "context", 0);
+    this->processMethod->parameters.push_back(this->rpcContextParam);    
+
+    this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
+    this->processMethod->parameters.push_back(this->errorParam);
+
+    this->requestData = new Variable(RPC_DATA_TYPE, "request");
+    this->processMethod->statements->Add(new VariableDeclaration(requestData,
+                new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
+
+    this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
+    this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
+                NULL_VALUE));
+}
+
+void
+DispatcherClass::AddMethod(const method_type* method)
+{
+    arg_type* arg;
+
+    // The if/switch statement
+    IfStatement* ifs = new IfStatement();
+        ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
+                1, this->actionParam);
+    StatementBlock* block = ifs->statements = new StatementBlock;
+    if (this->dispatchIfStatement == NULL) {
+        this->dispatchIfStatement = ifs;
+        this->processMethod->statements->Add(dispatchIfStatement);
+    } else {
+        this->dispatchIfStatement->elseif = ifs;
+        this->dispatchIfStatement = ifs;
+    }
+    
+    // The call to decl (from above)
+    MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);
+
+    // args
+    Variable* classLoader = NULL;
+    VariableFactory stubArgs("_arg");
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(t);
+        v->dimension = arg->type.dimension;
+
+        // Unmarshall the parameter
+        block->Add(new VariableDeclaration(v));
+        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+            generate_create_from_data(t, block, arg->name.data, v,
+                    this->requestData, &classLoader);
+        } else {
+            if (arg->type.dimension == 0) {
+                block->Add(new Assignment(v, new NewExpression(v->type)));
+            }
+            else if (arg->type.dimension == 1) {
+                generate_new_array(v->type, block, v, this->requestData);
+            }
+            else {
+                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
+                        __LINE__);
+            }
+        }
+
+        // Add that parameter to the method call
+        realCall->arguments.push_back(v);
+
+        arg = arg->next;
+    }
+
+    // Add a final parameter: RpcContext. Contains data about
+    // incoming request (e.g., certificate)
+    realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+
+    Type* returnType = NAMES.Search(method->type.type.data);
+    if (returnType == EVENT_FAKE_TYPE) {
+        returnType = VOID_TYPE;
+    }
+    
+    // the real call
+    bool first = true;
+    Variable* _result = NULL;
+    if (returnType == VOID_TYPE) {
+        block->Add(realCall);
+    } else {
+        _result = new Variable(returnType, "_result",
+                                method->type.dimension);
+        block->Add(new VariableDeclaration(_result, realCall));
+
+        // need the result RpcData
+        if (first) {
+            block->Add(new Assignment(this->resultData,
+                        new NewExpression(RPC_DATA_TYPE)));
+            first = false;
+        }
+
+        // marshall the return value
+        generate_write_to_data(returnType, block,
+                new StringLiteralExpression("_result"), _result, this->resultData);
+    }
+
+    // out parameters
+    int i = 0;
+    arg = method->args;
+    while (arg != NULL) {
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = stubArgs.Get(i++);
+
+        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+            // need the result RpcData
+            if (first) {
+                block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
+                first = false;
+            }
+
+            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
+                    v, this->resultData);
+        }
+
+        arg = arg->next;
+    }
+}
+
+void
+DispatcherClass::DoneWithMethods()
+{
+    if (this->dispatchIfStatement == NULL) {
+        return;
+    }
+
+    this->elements.push_back(this->processMethod);
+
+    IfStatement* fallthrough = new IfStatement();
+        fallthrough->statements = new StatementBlock;
+        fallthrough->statements->Add(new ReturnStatement(
+                    new MethodCall(SUPER_VALUE, "process", 4, 
+                    this->actionParam, this->requestParam, 
+                    this->rpcContextParam,
+                    this->errorParam)));
+    this->dispatchIfStatement->elseif = fallthrough;
+    IfStatement* s = new IfStatement;
+        s->statements = new StatementBlock;
+    this->processMethod->statements->Add(s);
+    s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
+    s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
+    s->elseif = new IfStatement;
+    s = s->elseif;
+    s->statements->Add(new ReturnStatement(NULL_VALUE));
+}
+
+// =================================================
+class RpcProxyClass : public Class
+{
+public:
+    RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
+    virtual ~RpcProxyClass();
+
+    Variable* endpoint;
+    Variable* broker;
+
+private:
+    void generate_ctor();
+    void generate_get_endpoint_info();
+};
+
+RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
+    :Class()
+{
+    this->comment = gather_comments(iface->comments_token->extra);
+    this->modifiers = PUBLIC;
+    this->what = Class::CLASS;
+    this->type = interfaceType;
+
+    // broker
+    this->broker = new Variable(RPC_BROKER_TYPE, "_broker");
+    this->elements.push_back(new Field(PRIVATE, this->broker));
+    // endpoint
+    this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
+    this->elements.push_back(new Field(PRIVATE, this->endpoint));
+
+    // methods
+    generate_ctor();
+    generate_get_endpoint_info();
+}
+
+RpcProxyClass::~RpcProxyClass()
+{
+}
+
+void
+RpcProxyClass::generate_ctor()
+{
+    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+    Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->name = class_name_leaf(this->type->Name());
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(broker);
+        ctor->parameters.push_back(endpoint);
+    this->elements.push_back(ctor);
+
+    ctor->statements->Add(new Assignment(this->broker, broker));
+    ctor->statements->Add(new Assignment(this->endpoint, endpoint));
+}
+
+void
+RpcProxyClass::generate_get_endpoint_info()
+{
+    Method* get = new Method;
+    get->modifiers = PUBLIC;
+    get->returnType = RPC_ENDPOINT_INFO_TYPE;
+    get->name = "getEndpointInfo";
+    get->statements = new StatementBlock;
+    this->elements.push_back(get);
+
+    get->statements->Add(new ReturnStatement(this->endpoint));
+}
+
+// =================================================
+class EventListenerClass : public DispatcherClass
+{
+public:
+    EventListenerClass(const interface_type* iface, Type* listenerType);
+    virtual ~EventListenerClass();
+
+    Variable* _listener;
+
+private:
+    void generate_ctor();
+};
+
+Expression*
+generate_get_listener_expression(Type* cast)
+{
+    return new Cast(cast, new MethodCall(THIS_VALUE, "getView"));
+}
+
+EventListenerClass::EventListenerClass(const interface_type* iface, Type* listenerType)
+    :DispatcherClass(iface, new FieldVariable(THIS_VALUE, "_listener"))
+{
+    this->modifiers = PRIVATE;
+    this->what = Class::CLASS;
+    this->type = new Type(iface->package ? iface->package : "",
+                        append(iface->name.data, ".Presenter"),
+                        Type::GENERATED, false, false, false);
+    this->extends = PRESENTER_BASE_TYPE;
+
+    this->_listener = new Variable(listenerType, "_listener");
+    this->elements.push_back(new Field(PRIVATE, this->_listener));
+
+    // methods
+    generate_ctor();
+}
+
+EventListenerClass::~EventListenerClass()
+{
+}
+
+void
+EventListenerClass::generate_ctor()
+{
+    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+    Variable* listener = new Variable(this->_listener->type, "listener");
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->name = class_name_leaf(this->type->Name());
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(broker);
+        ctor->parameters.push_back(listener);
+    this->elements.push_back(ctor);
+
+    ctor->statements->Add(new MethodCall("super", 2, broker, listener));
+    ctor->statements->Add(new Assignment(this->_listener, listener));
+}
+
+// =================================================
+class ListenerClass : public Class
+{
+public:
+    ListenerClass(const interface_type* iface);
+    virtual ~ListenerClass();
+
+    bool needed;
+
+private:
+    void generate_ctor();
+};
+
+ListenerClass::ListenerClass(const interface_type* iface)
+    :Class(),
+     needed(false)
+{
+    this->comment = "/** Extend this to listen to the events from this class. */";
+    this->modifiers = STATIC | PUBLIC ;
+    this->what = Class::CLASS;
+    this->type = new Type(iface->package ? iface->package : "",
+                        append(iface->name.data, ".Listener"),
+                        Type::GENERATED, false, false, false);
+    this->extends = PRESENTER_LISTENER_BASE_TYPE;
+}
+
+ListenerClass::~ListenerClass()
+{
+}
+
+// =================================================
+class EndpointBaseClass : public DispatcherClass
+{
+public:
+    EndpointBaseClass(const interface_type* iface);
+    virtual ~EndpointBaseClass();
+
+    bool needed;
+
+private:
+    void generate_ctor();
+};
+
+EndpointBaseClass::EndpointBaseClass(const interface_type* iface)
+    :DispatcherClass(iface, THIS_VALUE),
+     needed(false)
+{
+    this->comment = "/** Extend this to implement a link service. */";
+    this->modifiers = STATIC | PUBLIC | ABSTRACT;
+    this->what = Class::CLASS;
+    this->type = new Type(iface->package ? iface->package : "",
+                        append(iface->name.data, ".EndpointBase"),
+                        Type::GENERATED, false, false, false);
+    this->extends = RPC_CONNECTOR_TYPE;
+
+    // methods
+    generate_ctor();
+}
+
+EndpointBaseClass::~EndpointBaseClass()
+{
+}
+
+void
+EndpointBaseClass::generate_ctor()
+{
+    Variable* container = new Variable(RPC_CONTAINER_TYPE, "container");
+    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+	Variable* place = new Variable(PLACE_INFO_TYPE, "placeInfo");
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->name = class_name_leaf(this->type->Name());
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(container);
+        ctor->parameters.push_back(broker);
+        ctor->parameters.push_back(place);
+    this->elements.push_back(ctor);
+
+    ctor->statements->Add(new MethodCall("super", 3, container, broker, place));
+}
+
+// =================================================
+class ResultDispatcherClass : public Class
+{
+public:
+    ResultDispatcherClass();
+    virtual ~ResultDispatcherClass();
+
+    void AddMethod(int index, const string& name, Method** method, Variable** param);
+
+    bool needed;
+    Variable* methodId;
+    Variable* callback;
+    Method* onResultMethod;
+    Variable* resultParam;
+    SwitchStatement* methodSwitch;
+
+private:
+    void generate_ctor();
+    void generate_onResult();
+};
+
+ResultDispatcherClass::ResultDispatcherClass()
+    :Class(),
+     needed(false)
+{
+    this->modifiers = PRIVATE | FINAL;
+    this->what = Class::CLASS;
+    this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
+    this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
+
+    // methodId
+    this->methodId = new Variable(INT_TYPE, "methodId");
+    this->elements.push_back(new Field(PRIVATE, this->methodId));
+    this->callback = new Variable(OBJECT_TYPE, "callback");
+    this->elements.push_back(new Field(PRIVATE, this->callback));
+
+    // methods
+    generate_ctor();
+    generate_onResult();
+}
+
+ResultDispatcherClass::~ResultDispatcherClass()
+{
+}
+
+void
+ResultDispatcherClass::generate_ctor()
+{
+    Variable* methodIdParam = new Variable(INT_TYPE, "methId");
+    Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
+    Method* ctor = new Method;
+        ctor->modifiers = PUBLIC;
+        ctor->name = class_name_leaf(this->type->Name());
+        ctor->statements = new StatementBlock;
+        ctor->parameters.push_back(methodIdParam);
+        ctor->parameters.push_back(callbackParam);
+    this->elements.push_back(ctor);
+
+    ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
+    ctor->statements->Add(new Assignment(this->callback, callbackParam));
+}
+
+void
+ResultDispatcherClass::generate_onResult()
+{
+    this->onResultMethod = new Method;
+        this->onResultMethod->modifiers = PUBLIC;
+        this->onResultMethod->returnType = VOID_TYPE;
+        this->onResultMethod->returnTypeDimension = 0;
+        this->onResultMethod->name = "onResult";
+        this->onResultMethod->statements = new StatementBlock;
+    this->elements.push_back(this->onResultMethod);
+
+    this->resultParam = new Variable(BYTE_TYPE, "result", 1);
+    this->onResultMethod->parameters.push_back(this->resultParam);
+
+    this->methodSwitch = new SwitchStatement(this->methodId);
+    this->onResultMethod->statements->Add(this->methodSwitch);
+}
+
+void
+ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
+{
+    Method* m = new Method;
+        m->modifiers = PUBLIC;
+        m->returnType = VOID_TYPE;
+        m->returnTypeDimension = 0;
+        m->name = name;
+        m->statements = new StatementBlock;
+    *param = new Variable(BYTE_TYPE, "result", 1);
+    m->parameters.push_back(*param);
+    this->elements.push_back(m);
+    *method = m;
+
+    Case* c = new Case(format_int(index));
+    c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
+    c->statements->Add(new Break());
+
+    this->methodSwitch->cases.push_back(c);
+}
+
+// =================================================
+static void
+generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
+{
+    fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
+    exit(1);
+}
+
+static void
+generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
+                            Variable* data, Variable** cl)
+{
+    Expression* k = new StringLiteralExpression(key);
+    if (v->dimension == 0) {
+        t->CreateFromRpcData(addTo, k, v, data, cl);
+    }
+    if (v->dimension == 1) {
+        //t->ReadArrayFromRpcData(addTo, v, data, cl);
+        fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
+                __FILE__, __LINE__);
+    }
+}
+
+static void
+generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
+{
+    if (v->dimension == 0) {
+        t->WriteToRpcData(addTo, k, v, data, 0);
+    }
+    if (v->dimension == 1) {
+        //t->WriteArrayToParcel(addTo, v, data);
+        fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
+                __FILE__, __LINE__);
+    }
+}
+
+// =================================================
+static Type*
+generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
+{
+    arg_type* arg;
+
+    string resultsMethodName = results_method_name(method->name.data);
+    Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
+            Type::GENERATED, false, false, false);
+
+    if (!method->oneway) {
+        Class* resultsClass = new Class;
+            resultsClass->modifiers = STATIC | PUBLIC;
+            resultsClass->what = Class::INTERFACE;
+            resultsClass->type = resultsInterfaceType;
+
+        Method* resultMethod = new Method;
+            resultMethod->comment = gather_comments(method->comments_token->extra);
+            resultMethod->modifiers = PUBLIC;
+            resultMethod->returnType = VOID_TYPE;
+            resultMethod->returnTypeDimension = 0;
+            resultMethod->name = resultsMethodName;
+        if (0 != strcmp("void", method->type.type.data)) {
+            resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
+                        "_result", method->type.dimension));
+        }
+        arg = method->args;
+        while (arg != NULL) {
+            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+                resultMethod->parameters.push_back(new Variable(
+                                    NAMES.Search(arg->type.type.data), arg->name.data,
+                                    arg->type.dimension));
+            }
+            arg = arg->next;
+        }
+        resultsClass->elements.push_back(resultMethod);
+
+        if (resultMethod->parameters.size() > 0) {
+            proxyClass->elements.push_back(resultsClass);
+            return resultsInterfaceType;
+        } 
+    }
+    //delete resultsInterfaceType;
+    return NULL;
+}
+
+static void
+generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
+        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+    arg_type* arg;
+    Method* proxyMethod = new Method;
+        proxyMethod->comment = gather_comments(method->comments_token->extra);
+        proxyMethod->modifiers = PUBLIC;
+        proxyMethod->returnType = VOID_TYPE;
+        proxyMethod->returnTypeDimension = 0;
+        proxyMethod->name = method->name.data;
+        proxyMethod->statements = new StatementBlock;
+    proxyClass->elements.push_back(proxyMethod);
+
+    // The local variables
+    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+    proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+    // Add the arguments
+    arg = method->args;
+    while (arg != NULL) {
+        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
+            // Function signature
+            Type* t = NAMES.Search(arg->type.type.data);
+            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+            proxyMethod->parameters.push_back(v);
+
+            // Input parameter marshalling
+            generate_write_to_data(t, proxyMethod->statements,
+                    new StringLiteralExpression(arg->name.data), v, _data);
+        }
+        arg = arg->next;
+    }
+
+    // If there is a results interface for this class
+    Expression* resultParameter;
+    if (resultsInterfaceType != NULL) {
+        // Result interface parameter
+        Variable* resultListener = new Variable(resultsInterfaceType, "_result");
+        proxyMethod->parameters.push_back(resultListener);
+
+        // Add the results dispatcher callback
+        resultsDispatcherClass->needed = true;
+        resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
+                new LiteralExpression(format_int(index)), resultListener);
+    } else {
+        resultParameter = NULL_VALUE;
+    }
+
+    // All proxy methods take an error parameter
+    Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
+    proxyMethod->parameters.push_back(errorListener);
+
+    // Call the broker
+    proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"),
+                "sendRpc", 5,
+                proxyClass->endpoint,
+                new StringLiteralExpression(method->name.data),
+                new MethodCall(_data, "serialize"),
+                resultParameter,
+                errorListener));
+}
+
+static void
+generate_result_dispatcher_method(const method_type* method,
+        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
+{
+    arg_type* arg;
+    Method* dispatchMethod;
+    Variable* dispatchParam;
+    resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
+
+    Variable* classLoader = NULL;
+    Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
+    dispatchMethod->statements->Add(new VariableDeclaration(resultData,
+                new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
+
+    // The callback method itself
+    MethodCall* realCall = new MethodCall(
+            new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
+            results_method_name(method->name.data));
+
+    // The return value
+    {
+        Type* t = NAMES.Search(method->type.type.data);
+        if (t != VOID_TYPE) {
+            Variable* rv = new Variable(t, "rv");
+            dispatchMethod->statements->Add(new VariableDeclaration(rv));
+            generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
+                    resultData, &classLoader);
+            realCall->arguments.push_back(rv);
+        }
+    }
+
+    VariableFactory stubArgs("arg");
+    arg = method->args;
+    while (arg != NULL) {
+        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
+            // Unmarshall the results
+            Type* t = NAMES.Search(arg->type.type.data);
+            Variable* v = stubArgs.Get(t);
+            dispatchMethod->statements->Add(new VariableDeclaration(v));
+
+            generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
+                    resultData, &classLoader);
+
+            // Add the argument to the callback
+            realCall->arguments.push_back(v);
+        }
+        arg = arg->next;
+    }
+
+    // Call the callback method
+    dispatchMethod->statements->Add(realCall);
+}
+
+static void
+generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
+        EndpointBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
+        int index)
+{
+    arg_type* arg;
+
+    // == the callback interface for results ================================
+    // the service base class
+    Type* resultsInterfaceType = generate_results_method(method, proxyClass);
+    
+    // == the method in the proxy class =====================================
+    generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
+
+    // == the method in the result dispatcher class =========================
+    if (resultsInterfaceType != NULL) {
+        generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
+                index);
+    }
+
+    // == The abstract method that the service developers implement ==========
+    Method* decl = new Method;
+        decl->comment = gather_comments(method->comments_token->extra);
+        decl->modifiers = PUBLIC | ABSTRACT;
+        decl->returnType = NAMES.Search(method->type.type.data);
+        decl->returnTypeDimension = method->type.dimension;
+        decl->name = method->name.data;
+    arg = method->args;
+    while (arg != NULL) {
+        decl->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+        arg = arg->next;
+    }
+
+    // Add the default RpcContext param to all methods
+    decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+	
+    serviceBaseClass->elements.push_back(decl);
+    
+
+    // == the dispatch method in the service base class ======================
+    serviceBaseClass->AddMethod(method);
+}
+
+static void
+generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
+        EndpointBaseClass* serviceBaseClass, ListenerClass* listenerClass,
+        EventListenerClass* presenterClass, int index)
+{
+    arg_type* arg;
+    listenerClass->needed = true;
+
+    // == the push method in the service base class =========================
+    Method* push = new Method;
+        push->modifiers = PUBLIC;
+        push->name = push_method_name(method->name.data);
+        push->statements = new StatementBlock;
+        push->returnType = VOID_TYPE;
+    serviceBaseClass->elements.push_back(push);
+
+    // The local variables
+    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
+    push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
+
+    // Add the arguments
+    arg = method->args;
+    while (arg != NULL) {
+        // Function signature
+        Type* t = NAMES.Search(arg->type.type.data);
+        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
+        push->parameters.push_back(v);
+
+        // Input parameter marshalling
+        generate_write_to_data(t, push->statements,
+                new StringLiteralExpression(arg->name.data), v, _data);
+
+        arg = arg->next;
+    }
+
+    // Send the notifications
+    push->statements->Add(new MethodCall("pushEvent", 2,
+                new StringLiteralExpression(method->name.data),
+                new MethodCall(_data, "serialize")));
+
+    // == the event callback dispatcher method  ====================================
+    presenterClass->AddMethod(method);
+
+    // == the event method in the listener base class =====================
+    Method* event = new Method;
+        event->modifiers = PUBLIC;
+        event->name = method->name.data;
+        event->statements = new StatementBlock;
+        event->returnType = VOID_TYPE;
+    listenerClass->elements.push_back(event);
+    arg = method->args;
+    while (arg != NULL) {
+        event->parameters.push_back(new Variable(
+                            NAMES.Search(arg->type.type.data), arg->name.data,
+                            arg->type.dimension));
+        arg = arg->next;
+    }
+
+    // Add a final parameter: RpcContext. Contains data about
+    // incoming request (e.g., certificate)
+    event->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
+}
+
+static void
+generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
+{
+    // AndroidAtHomePresenter _presenter;
+    // void startListening(Listener listener) {
+    //     stopListening();
+    //     _presenter = new Presenter(_broker, listener);
+    //     _presenter.startListening(_endpoint);
+    // }
+    // void stopListening() {
+    //     if (_presenter != null) {
+    //         _presenter.stopListening();
+    //     }
+    // }
+
+    Variable* _presenter = new Variable(presenterType, "_presenter");
+    proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
+
+    Variable* listener = new Variable(listenerType, "listener");
+
+    Method* startListeningMethod = new Method;
+        startListeningMethod->modifiers = PUBLIC;
+        startListeningMethod->returnType = VOID_TYPE;
+        startListeningMethod->name = "startListening";
+        startListeningMethod->statements = new StatementBlock;
+        startListeningMethod->parameters.push_back(listener);
+    proxyClass->elements.push_back(startListeningMethod);
+
+    startListeningMethod->statements->Add(new MethodCall(THIS_VALUE, "stopListening"));
+    startListeningMethod->statements->Add(new Assignment(_presenter,
+                new NewExpression(presenterType, 2, proxyClass->broker, listener)));
+    startListeningMethod->statements->Add(new MethodCall(_presenter,
+                "startListening", 1, proxyClass->endpoint));
+
+    Method* stopListeningMethod = new Method;
+        stopListeningMethod->modifiers = PUBLIC;
+        stopListeningMethod->returnType = VOID_TYPE;
+        stopListeningMethod->name = "stopListening";
+        stopListeningMethod->statements = new StatementBlock;
+    proxyClass->elements.push_back(stopListeningMethod);
+
+    IfStatement* ifst = new IfStatement;
+        ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
+    stopListeningMethod->statements->Add(ifst);
+
+    ifst->statements->Add(new MethodCall(_presenter, "stopListening"));
+    ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
+}
+
+Class*
+generate_rpc_interface_class(const interface_type* iface)
+{
+    // the proxy class
+    InterfaceType* interfaceType = static_cast<InterfaceType*>(
+        NAMES.Find(iface->package, iface->name.data));
+    RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
+
+    // the listener class
+    ListenerClass* listener = new ListenerClass(iface);
+
+    // the presenter class
+    EventListenerClass* presenter = new EventListenerClass(iface, listener->type);
+
+    // the service base class
+    EndpointBaseClass* base = new EndpointBaseClass(iface);
+    proxy->elements.push_back(base);
+
+    // the result dispatcher
+    ResultDispatcherClass* results = new ResultDispatcherClass();
+
+    // all the declared methods of the proxy
+    int index = 0;
+    interface_item_type* item = iface->interface_items;
+    while (item != NULL) {
+        if (item->item_type == METHOD_TYPE) {
+            if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
+                generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
+            } else {
+                generate_regular_method((method_type*)item, proxy, base, results, index);
+            }
+        }
+        item = item->next;
+        index++;
+    }
+    presenter->DoneWithMethods();
+    base->DoneWithMethods();
+
+    // only add this if there are methods with results / out parameters
+    if (results->needed) {
+        proxy->elements.push_back(results);
+    }
+    if (listener->needed) {
+        proxy->elements.push_back(listener);
+        proxy->elements.push_back(presenter);
+        generate_listener_methods(proxy, presenter->type, listener->type);
+    }
+
+    return proxy;
+}
diff --git a/tools/layoutlib/bridge/.settings/README.txt b/tools/layoutlib/bridge/.settings/README.txt
new file mode 100644
index 0000000..9120b20
--- /dev/null
+++ b/tools/layoutlib/bridge/.settings/README.txt
@@ -0,0 +1,2 @@
+Copy this in eclipse project as a .settings folder at the root.
+This ensure proper compilation compliance and warning/error levels.
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/.settings/org.eclipse.jdt.core.prefs b/tools/layoutlib/bridge/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..5381a0e
--- /dev/null
+++ b/tools/layoutlib/bridge/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,93 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.nonnull=com.android.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=com.android.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled
+org.eclipse.jdt.core.compiler.annotation.nullable=com.android.annotations.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/tools/layoutlib/bridge/resources/bars/action_bar.xml b/tools/layoutlib/bridge/resources/bars/action_bar.xml
index 51983f2..7adc5af 100644
--- a/tools/layoutlib/bridge/resources/bars/action_bar.xml
+++ b/tools/layoutlib/bridge/resources/bars/action_bar.xml
@@ -1,9 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
-	<ImageView
-			android:layout_height="wrap_content"
-			android:layout_width="wrap_content"/>
-	<TextView
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"/>
+    <include layout="@android:layout/action_bar_home" />
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
 </merge>
diff --git a/tools/layoutlib/bridge/src/android/animation/AnimationThread.java b/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
index af83c61..b46134a 100644
--- a/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
+++ b/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
@@ -23,11 +23,10 @@
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
 
-import android.animation.ValueAnimator;
 import android.os.Handler;
 import android.os.Handler_Delegate;
-import android.os.Message;
 import android.os.Handler_Delegate.IHandlerCallback;
+import android.os.Message;
 
 import java.util.PriorityQueue;
 import java.util.Queue;
@@ -57,6 +56,7 @@
             mUptimeMillis = uptimeMillis;
         }
 
+        @Override
         public int compareTo(MessageBundle bundle) {
             if (mUptimeMillis < bundle.mUptimeMillis) {
                 return -1;
@@ -85,6 +85,7 @@
         Bridge.prepareThread();
         try {
             Handler_Delegate.setCallback(new IHandlerCallback() {
+                @Override
                 public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
                     if (msg.what == ValueAnimator.ANIMATION_START /*||
                             FIXME: The ANIMATION_FRAME message no longer exists.  Instead,
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index 9a8cf04..65a75b0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -105,6 +105,7 @@
             mTileModeY = tileModeY;
         }
 
+        @Override
         public java.awt.PaintContext createContext(
                 java.awt.image.ColorModel      colorModel,
                 java.awt.Rectangle             deviceBounds,
@@ -148,13 +149,16 @@
                 mColorModel = colorModel;
             }
 
+            @Override
             public void dispose() {
             }
 
+            @Override
             public java.awt.image.ColorModel getColorModel() {
                 return mColorModel;
             }
 
+            @Override
             public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
                 java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
                         java.awt.image.BufferedImage.TYPE_INT_ARGB);
@@ -240,6 +244,7 @@
         }
 
 
+        @Override
         public int getTransparency() {
             return java.awt.Paint.TRANSLUCENT;
         }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index f797836..16f1575 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -291,6 +291,7 @@
             Paint paint) {
         draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
                 false /*forceSrcMode*/, new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         for (int i = 0 ; i < count ; i += 4) {
                             graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
@@ -619,6 +620,7 @@
         final int h = canvasDelegate.mBitmap.getImage().getHeight();
         draw(nativeCanvas, new GcSnapshot.Drawable() {
 
+            @Override
             public void draw(Graphics2D graphics, Paint_Delegate paint) {
                 // reset its transform just in case
                 graphics.setTransform(new AffineTransform());
@@ -651,6 +653,7 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
                     }
@@ -669,6 +672,7 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         int style = paintDelegate.getStyle();
 
@@ -693,6 +697,7 @@
         if (oval.right > oval.left && oval.bottom > oval.top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                     new GcSnapshot.Drawable() {
+                        @Override
                         public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                             int style = paintDelegate.getStyle();
 
@@ -728,6 +733,7 @@
         if (oval.right > oval.left && oval.bottom > oval.top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                     new GcSnapshot.Drawable() {
+                        @Override
                         public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                             int style = paintDelegate.getStyle();
 
@@ -757,6 +763,7 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         int style = paintDelegate.getStyle();
 
@@ -789,6 +796,7 @@
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                         Shape shape = pathDelegate.getJavaShape();
                         int style = paintDelegate.getStyle();
@@ -892,6 +900,7 @@
 
         draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paint) {
                         if (paint != null && paint.isFilterBitmap()) {
                             graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
@@ -931,6 +940,7 @@
         final AffineTransform mtx = matrixDelegate.getAffineTransform();
 
         canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+                @Override
                 public void draw(Graphics2D graphics, Paint_Delegate paint) {
                     if (paint != null && paint.isFilterBitmap()) {
                         graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
@@ -970,6 +980,7 @@
             final float startX, final float startY, int flags, int paint) {
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
+            @Override
             public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
                 // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
                 // Any change to this method should be reflected in Paint.measureText
@@ -1279,6 +1290,7 @@
 
         draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
                 new GcSnapshot.Drawable() {
+                    @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paint) {
                         if (paint != null && paint.isFilterBitmap()) {
                             graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
index 38c092d..7475c22 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
@@ -87,6 +87,7 @@
             mTileMode = tileMode;
         }
 
+        @Override
         public int getTransparency() {
             return java.awt.Paint.TRANSLUCENT;
         }
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index a2ba758..f117fca 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -132,6 +132,7 @@
             mDSize2 = mDx * mDx + mDy * mDy;
         }
 
+        @Override
         public java.awt.PaintContext createContext(
                 java.awt.image.ColorModel      colorModel,
                 java.awt.Rectangle             deviceBounds,
@@ -176,13 +177,16 @@
                 mColorModel = colorModel;
             }
 
+            @Override
             public void dispose() {
             }
 
+            @Override
             public java.awt.image.ColorModel getColorModel() {
                 return mColorModel;
             }
 
+            @Override
             public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
                 java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
                         java.awt.image.BufferedImage.TYPE_INT_ARGB);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index 451edd2..5df2a21 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -474,7 +474,7 @@
         }
 
         Matrix_Delegate other = sManager.getDelegate(other_matrix);
-        if (d == null) {
+        if (other == null) {
             return false;
         }
 
@@ -570,7 +570,7 @@
         }
 
         Matrix_Delegate other = sManager.getDelegate(other_matrix);
-        if (d == null) {
+        if (other == null) {
             return false;
         }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index 5e882ce..be27b54 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -215,6 +215,7 @@
         Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
 
         canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+                @Override
                 public void draw(Graphics2D graphics, Paint_Delegate paint) {
                     chunkObject.draw(bitmap_delegate.getImage(), graphics,
                             left, top, right - left, bottom - top, destDensity, srcDensity);
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index 9bf78b4..3fe45fa 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -118,6 +118,7 @@
             mRadius = radius;
         }
 
+        @Override
         public java.awt.PaintContext createContext(
                 java.awt.image.ColorModel     colorModel,
                 java.awt.Rectangle            deviceBounds,
@@ -162,13 +163,16 @@
                 mColorModel = colorModel;
             }
 
+            @Override
             public void dispose() {
             }
 
+            @Override
             public java.awt.image.ColorModel getColorModel() {
                 return mColorModel;
             }
 
+            @Override
             public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
                 java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
                         java.awt.image.BufferedImage.TYPE_INT_ARGB);
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index 966e06e..13ae12e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -110,6 +110,7 @@
             mCy = cy;
         }
 
+        @Override
         public java.awt.PaintContext createContext(
                 java.awt.image.ColorModel     colorModel,
                 java.awt.Rectangle            deviceBounds,
@@ -154,13 +155,16 @@
                 mColorModel = colorModel;
             }
 
+            @Override
             public void dispose() {
             }
 
+            @Override
             public java.awt.image.ColorModel getColorModel() {
                 return mColorModel;
             }
 
+            @Override
             public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
                 java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
                         java.awt.image.BufferedImage.TYPE_INT_ARGB);
diff --git a/tools/layoutlib/bridge/src/android/view/SurfaceView.java b/tools/layoutlib/bridge/src/android/view/SurfaceView.java
index ce32da9..6aa4b3b 100644
--- a/tools/layoutlib/bridge/src/android/view/SurfaceView.java
+++ b/tools/layoutlib/bridge/src/android/view/SurfaceView.java
@@ -27,7 +27,7 @@
  * Mock version of the SurfaceView.
  * Only non override public methods from the real SurfaceView have been added in there.
  * Methods that take an unknown class as parameter or as return object, have been removed for now.
- * 
+ *
  * TODO: generate automatically.
  *
  */
@@ -36,7 +36,7 @@
     public SurfaceView(Context context) {
         this(context, null);
     }
-    
+
     public SurfaceView(Context context, AttributeSet attrs) {
         this(context, attrs , 0);
     }
@@ -44,53 +44,66 @@
     public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
     }
-    
+
     public SurfaceHolder getHolder() {
         return mSurfaceHolder;
     }
 
     private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
-        
+
+        @Override
         public boolean isCreating() {
             return false;
         }
 
+        @Override
         public void addCallback(Callback callback) {
         }
 
+        @Override
         public void removeCallback(Callback callback) {
         }
-        
+
+        @Override
         public void setFixedSize(int width, int height) {
         }
 
+        @Override
         public void setSizeFromLayout() {
         }
 
+        @Override
         public void setFormat(int format) {
         }
 
+        @Override
         public void setType(int type) {
         }
 
+        @Override
         public void setKeepScreenOn(boolean screenOn) {
         }
-        
+
+        @Override
         public Canvas lockCanvas() {
             return null;
         }
 
+        @Override
         public Canvas lockCanvas(Rect dirty) {
             return null;
         }
 
+        @Override
         public void unlockCanvasAndPost(Canvas canvas) {
         }
 
+        @Override
         public Surface getSurface() {
             return null;
         }
 
+        @Override
         public Rect getSurfaceFrame() {
             return null;
         }
diff --git a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
index 9efdcaf..3017292 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
@@ -43,28 +43,33 @@
 
     private static class FakeTextServicesManager implements ITextServicesManager {
 
+        @Override
         public void finishSpellCheckerService(ISpellCheckerSessionListener arg0)
                 throws RemoteException {
             // TODO Auto-generated method stub
 
         }
 
+        @Override
         public SpellCheckerInfo getCurrentSpellChecker(String arg0) throws RemoteException {
             // TODO Auto-generated method stub
             return null;
         }
 
+        @Override
         public SpellCheckerSubtype getCurrentSpellCheckerSubtype(String arg0, boolean arg1)
                 throws RemoteException {
             // TODO Auto-generated method stub
             return null;
         }
 
+        @Override
         public SpellCheckerInfo[] getEnabledSpellCheckers() throws RemoteException {
             // TODO Auto-generated method stub
             return null;
         }
 
+        @Override
         public void getSpellCheckerService(String arg0, String arg1,
                 ITextServicesSessionListener arg2, ISpellCheckerSessionListener arg3, Bundle arg4)
                 throws RemoteException {
@@ -72,26 +77,31 @@
 
         }
 
+        @Override
         public boolean isSpellCheckerEnabled() throws RemoteException {
             // TODO Auto-generated method stub
             return false;
         }
 
+        @Override
         public void setCurrentSpellChecker(String arg0, String arg1) throws RemoteException {
             // TODO Auto-generated method stub
 
         }
 
+        @Override
         public void setCurrentSpellCheckerSubtype(String arg0, int arg1) throws RemoteException {
             // TODO Auto-generated method stub
 
         }
 
+        @Override
         public void setSpellCheckerEnabled(boolean arg0) throws RemoteException {
             // TODO Auto-generated method stub
 
         }
 
+        @Override
         public IBinder asBinder() {
             // TODO Auto-generated method stub
             return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index c91a3bf..e28866e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -19,6 +19,7 @@
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderResult;
 import android.content.ContentValues;
+import android.content.ICancellationSignal;
 import android.content.IContentProvider;
 import android.content.OperationApplicationException;
 import android.content.res.AssetFileDescriptor;
@@ -90,8 +91,8 @@
     }
 
     @Override
-    public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4)
-            throws RemoteException {
+    public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4,
+            ICancellationSignal arg5) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
@@ -122,4 +123,9 @@
         return null;
     }
 
+    @Override
+    public ICancellationSignal createCancellationSignal() throws RemoteException {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 2a52888..6afdfbe 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -37,151 +37,185 @@
  */
 public class BridgeIInputMethodManager implements IInputMethodManager {
 
+    @Override
     public void addClient(IInputMethodClient arg0, IInputContext arg1, int arg2, int arg3)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void finishInput(IInputMethodClient arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public InputMethodSubtype getCurrentInputMethodSubtype() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public List<InputMethodInfo> getEnabledInputMethodList() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo arg0,
             boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public List<InputMethodInfo> getInputMethodList() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public InputMethodSubtype getLastInputMethodSubtype() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public List getShortcutInputMethodsAndSubtypes() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public void hideMySoftInput(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean hideSoftInput(IInputMethodClient arg0, int arg1, ResultReceiver arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean notifySuggestionPicked(SuggestionSpan arg0, String arg1, int arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void registerSuggestionSpansForNotification(SuggestionSpan[] arg0)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void removeClient(IInputMethodClient arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAdditionalInputMethodSubtypes(String arg0, InputMethodSubtype[] arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
     }
 
+    @Override
     public boolean setCurrentInputMethodSubtype(InputMethodSubtype arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void setImeWindowStatus(IBinder arg0, int arg1, int arg2) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setInputMethod(IBinder arg0, String arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setInputMethodAndSubtype(IBinder arg0, String arg1, InputMethodSubtype arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean setInputMethodEnabled(String arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void showInputMethodAndSubtypeEnablerFromClient(IInputMethodClient arg0, String arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void showInputMethodPickerFromClient(IInputMethodClient arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void showMySoftInput(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean showSoftInput(IInputMethodClient arg0, int arg1, ResultReceiver arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public InputBindResult startInput(IInputMethodClient arg0, IInputContext arg1, EditorInfo arg2,
             boolean arg3, boolean arg4) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public boolean switchToLastInputMethod(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
+        public boolean switchToNextInputMethod(IBinder arg0, boolean arg1) throws RemoteException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
     public void updateStatusIcon(IBinder arg0, String arg1, int arg2) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void windowGainedFocus(IInputMethodClient arg0, IBinder arg1, boolean arg2,
             boolean arg3, int arg4, boolean arg5, int arg6) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public IBinder asBinder() {
         // TODO Auto-generated method stub
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
index d208408..f5912e7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
@@ -37,6 +37,7 @@
         mAttributes = attributes;
     }
 
+    @Override
     public String getAttributeValue(String namespace, String name) {
         if (BridgeConstants.NS_RESOURCES.equals(namespace)) {
             return mAttributes.get(name);
@@ -49,93 +50,114 @@
     // BridgeContext#obtainStyledAttributes(AttributeSet, int[], int, int)
     // Should they ever be called, we'll just implement them on a need basis.
 
+    @Override
     public int getAttributeCount() {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getAttributeName(int index) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getAttributeValue(int index) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getPositionDescription() {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeNameResource(int index) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeListValue(String namespace, String attribute,
             String[] options, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public boolean getAttributeBooleanValue(String namespace, String attribute,
             boolean defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeResourceValue(String namespace, String attribute,
             int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeIntValue(String namespace, String attribute,
             int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeUnsignedIntValue(String namespace, String attribute,
             int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public float getAttributeFloatValue(String namespace, String attribute,
             float defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeListValue(int index,
             String[] options, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeResourceValue(int index, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeIntValue(int index, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getAttributeUnsignedIntValue(int index, int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public float getAttributeFloatValue(int index, float defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getIdAttribute() {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public String getClassAttribute() {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getIdAttributeResourceValue(int defaultValue) {
         throw new UnsupportedOperationException();
     }
 
+    @Override
     public int getStyleAttribute() {
         throw new UnsupportedOperationException();
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index e13380e..79606a4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -24,72 +24,67 @@
 import android.os.RemoteException;
 import android.view.DragEvent;
 import android.view.IWindow;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
 
 /**
  * Implementation of {@link IWindow} to pass to the AttachInfo.
  */
 public final class BridgeWindow implements IWindow {
 
+    @Override
     public void dispatchAppVisibility(boolean arg0) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void dispatchGetNewSurface() throws RemoteException {
         // pass for now.
     }
-
-    public void dispatchKey(KeyEvent arg0) throws RemoteException {
-        // pass for now.
-    }
-
-    public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
-        // pass for now.
-    }
-
-    public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2)
-    throws RemoteException {
-        // pass for now.
-    }
-
+    @Override
     public void executeCommand(String arg0, String arg1, ParcelFileDescriptor arg2)
             throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
             throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
             boolean sync) {
         // pass for now.
     }
 
+    @Override
     public void dispatchWallpaperCommand(String action, int x, int y,
             int z, Bundle extras, boolean sync) {
         // pass for now.
     }
 
+    @Override
     public void closeSystemDialogs(String reason) {
         // pass for now.
     }
 
+    @Override
     public void dispatchDragEvent(DragEvent event) {
         // pass for now.
     }
 
+    @Override
     public void dispatchSystemUiVisibilityChanged(int seq, int globalUi,
             int localValue, int localChanges) {
         // pass for now.
     }
 
+    @Override
     public IBinder asBinder() {
         // pass for now.
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 516725e..bef2c95 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -67,288 +67,345 @@
 
     // ---- implementation of IWindowManager that we care about ----
 
+    @Override
     public int getRotation() throws RemoteException {
         return mRotation;
     }
 
+    @Override
     public int getMaximumSizeDimension() throws RemoteException {
         return 0;
     }
 
+    @Override
     public void getDisplaySize(Point arg0) throws RemoteException {
     }
 
+    @Override
     public void getRealDisplaySize(Point arg0) throws RemoteException {
     }
 
     // ---- unused implementation of IWindowManager ----
 
+    @Override
     public boolean canStatusBarHide() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void addWindowToken(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void clearForcedDisplaySize() throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void closeSystemDialogs(String arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void disableKeyguard(IBinder arg0, String arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void executeAppTransition() throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void exitKeyguardSecurely(IOnKeyguardExitResult arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void freezeRotation(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public float getAnimationScale(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public float[] getAnimationScales() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int getAppOrientation(IApplicationToken arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getDPadKeycodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getDPadScancodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
 
+    @Override
     public InputDevice getInputDevice(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int[] getInputDeviceIds() throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int getKeycodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getKeycodeStateForDevice(int arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
 
+    @Override
     public int getPendingAppTransition() throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
 
+    @Override
     public int getScancodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getScancodeStateForDevice(int arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getSwitchState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getSwitchStateForDevice(int arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getTrackballKeycodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public int getTrackballScancodeState(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public boolean hasKeys(int[] arg0, boolean[] arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean inKeyguardRestrictedInputMode() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean injectInputEventNoWait(InputEvent arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean injectKeyEvent(KeyEvent arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean injectPointerEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean injectTrackballEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean inputMethodClientHasFocus(IInputMethodClient arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean isKeyguardLocked() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean isKeyguardSecure() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public boolean isViewServerRunning() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public InputChannel monitorInput(String arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public void moveAppToken(int arg0, IBinder arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void moveAppTokensToBottom(List<IBinder> arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void moveAppTokensToTop(List<IBinder> arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public IWindowSession openSession(IInputMethodClient arg0, IInputContext arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public void overridePendingAppTransition(String arg0, int arg1, int arg2)
             throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void prepareAppTransition(int arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void reenableKeyguard(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void removeAppToken(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void removeWindowToken(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void resumeKeyDispatching(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public Bitmap screenshotApplications(IBinder arg0, int arg1, int arg2) throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public void setAnimationScale(int arg0, float arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAnimationScales(float[] arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAppGroupId(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
             CharSequence arg4, int arg5, int arg6, int arg7, IBinder arg8, boolean arg9)
             throws RemoteException {
@@ -356,122 +413,147 @@
 
     }
 
+    @Override
     public void setAppVisibility(IBinder arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setAppWillBeHidden(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setEventDispatching(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setFocusedApp(IBinder arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setForcedDisplaySize(int arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setInTouchMode(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setNewConfiguration(Configuration arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setPointerSpeed(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void updateRotation(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void setStrictModeVisualIndicatorPreference(String arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void showStrictModeViolation(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean startViewServer(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void statusBarVisibilityChanged(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public boolean stopViewServer() throws RemoteException {
         // TODO Auto-generated method stub
         return false;
     }
 
+    @Override
     public void thawRotation() throws RemoteException {
         // TODO Auto-generated method stub
 
     }
 
+    @Override
     public Configuration updateOrientationFromAppTokens(Configuration arg0, IBinder arg1)
             throws RemoteException {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int watchRotation(IRotationWatcher arg0) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
     }
 
+    @Override
     public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
         // TODO Auto-generated method stub
     }
-    
+
+    @Override
     public IBinder asBinder() {
         // TODO Auto-generated method stub
         return null;
     }
 
+    @Override
     public int getPreferredOptionsPanelGravity() throws RemoteException {
         return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
     }
 
+    @Override
     public void dismissKeyguard() {
     }
 
+    @Override
     public boolean hasNavigationBar() {
         return false; // should this return something else?
     }
 
+    @Override
     public void lockNow() {
         // TODO Auto-generated method stub
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index a640a913..d3721ed 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -26,7 +26,6 @@
 import android.view.IWindow;
 import android.view.IWindowSession;
 import android.view.InputChannel;
-import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.WindowManager.LayoutParams;
@@ -37,6 +36,7 @@
  */
 public final class BridgeWindowSession implements IWindowSession {
 
+    @Override
     public int add(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3,
             InputChannel outInputchannel)
             throws RemoteException {
@@ -44,40 +44,30 @@
         return 0;
     }
 
+    @Override
     public int addWithoutInputChannel(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3)
             throws RemoteException {
         // pass for now.
         return 0;
     }
 
+    @Override
     public void finishDrawing(IWindow arg0) throws RemoteException {
         // pass for now.
     }
 
-    public void finishKey(IWindow arg0) throws RemoteException {
-        // pass for now.
-    }
-
+    @Override
     public boolean getInTouchMode() throws RemoteException {
         // pass for now.
         return false;
     }
 
+    @Override
     public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
         // pass for now.
         return false;
     }
-
-    public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
-        // pass for now.
-        return null;
-    }
-
-    public MotionEvent getPendingTrackballMove(IWindow arg0) throws RemoteException {
-        // pass for now.
-        return null;
-    }
-
+    @Override
     public int relayout(IWindow arg0, int seq, LayoutParams arg1, int arg2, int arg3, int arg4,
             int arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
             throws RemoteException {
@@ -85,35 +75,43 @@
         return 0;
     }
 
+    @Override
     public void performDeferredDestroy(IWindow window) {
         // pass for now.
     }
 
+    @Override
     public boolean outOfMemory(IWindow window) throws RemoteException {
         return false;
     }
 
+    @Override
     public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
         // pass for now.
     }
 
+    @Override
     public void remove(IWindow arg0) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void setInTouchMode(boolean arg0) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void setTransparentRegion(IWindow arg0, Region arg1) throws RemoteException {
         // pass for now.
     }
 
+    @Override
     public void setInsets(IWindow window, int touchable, Rect contentInsets,
             Rect visibleInsets, Region touchableRegion) {
         // pass for now.
     }
 
+    @Override
     public IBinder prepareDrag(IWindow window, int flags,
             int thumbnailWidth, int thumbnailHeight, Surface outSurface)
             throws RemoteException {
@@ -121,6 +119,7 @@
         return null;
     }
 
+    @Override
     public boolean performDrag(IWindow window, IBinder dragToken,
             float touchX, float touchY, float thumbCenterX, float thumbCenterY,
             ClipData data)
@@ -129,49 +128,47 @@
         return false;
     }
 
+    @Override
     public void reportDropResult(IWindow window, boolean consumed) throws RemoteException {
         // pass for now
     }
 
+    @Override
     public void dragRecipientEntered(IWindow window) throws RemoteException {
         // pass for now
     }
 
+    @Override
     public void dragRecipientExited(IWindow window) throws RemoteException {
         // pass for now
     }
 
+    @Override
     public void setWallpaperPosition(IBinder window, float x, float y,
         float xStep, float yStep) {
         // pass for now.
     }
 
+    @Override
     public void wallpaperOffsetsComplete(IBinder window) {
         // pass for now.
     }
 
+    @Override
     public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
             int z, Bundle extras, boolean sync) {
         // pass for now.
         return null;
     }
 
+    @Override
     public void wallpaperCommandComplete(IBinder window, Bundle result) {
         // pass for now.
     }
 
-    public void closeSystemDialogs(String reason) {
-        // pass for now.
-    }
-
+    @Override
     public IBinder asBinder() {
         // pass for now.
         return null;
     }
-
-    public IBinder prepareDrag(IWindow arg0, boolean arg1, int arg2, int arg3, Surface arg4)
-            throws RemoteException {
-        // TODO Auto-generated method stub
-        return null;
-    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
index f8ed4f7..ac8712e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
@@ -95,6 +95,7 @@
 
     // ------- XmlResourceParser implementation
 
+    @Override
     public void setFeature(String name, boolean state)
             throws XmlPullParserException {
         if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) {
@@ -106,6 +107,7 @@
         throw new XmlPullParserException("Unsupported feature: " + name);
     }
 
+    @Override
     public boolean getFeature(String name) {
         if (FEATURE_PROCESS_NAMESPACES.equals(name)) {
             return true;
@@ -116,82 +118,101 @@
         return false;
     }
 
+    @Override
     public void setProperty(String name, Object value) throws XmlPullParserException {
         throw new XmlPullParserException("setProperty() not supported");
     }
 
+    @Override
     public Object getProperty(String name) {
         return null;
     }
 
+    @Override
     public void setInput(Reader in) throws XmlPullParserException {
         mParser.setInput(in);
     }
 
+    @Override
     public void setInput(InputStream inputStream, String inputEncoding)
             throws XmlPullParserException {
         mParser.setInput(inputStream, inputEncoding);
     }
 
+    @Override
     public void defineEntityReplacementText(String entityName,
             String replacementText) throws XmlPullParserException {
         throw new XmlPullParserException(
                 "defineEntityReplacementText() not supported");
     }
 
+    @Override
     public String getNamespacePrefix(int pos) throws XmlPullParserException {
         throw new XmlPullParserException("getNamespacePrefix() not supported");
     }
 
+    @Override
     public String getInputEncoding() {
         return null;
     }
 
+    @Override
     public String getNamespace(String prefix) {
         throw new RuntimeException("getNamespace() not supported");
     }
 
+    @Override
     public int getNamespaceCount(int depth) throws XmlPullParserException {
         throw new XmlPullParserException("getNamespaceCount() not supported");
     }
 
+    @Override
     public String getPositionDescription() {
         return "Binary XML file line #" + getLineNumber();
     }
 
+    @Override
     public String getNamespaceUri(int pos) throws XmlPullParserException {
         throw new XmlPullParserException("getNamespaceUri() not supported");
     }
 
+    @Override
     public int getColumnNumber() {
         return -1;
     }
 
+    @Override
     public int getDepth() {
         return mParser.getDepth();
     }
 
+    @Override
     public String getText() {
         return mParser.getText();
     }
 
+    @Override
     public int getLineNumber() {
         return mParser.getLineNumber();
     }
 
+    @Override
     public int getEventType() {
         return mEventType;
     }
 
+    @Override
     public boolean isWhitespace() throws XmlPullParserException {
         // Original comment: whitespace was stripped by aapt.
         return mParser.isWhitespace();
     }
 
+    @Override
     public String getPrefix() {
         throw new RuntimeException("getPrefix not supported");
     }
 
+    @Override
     public char[] getTextCharacters(int[] holderForStartAndLength) {
         String txt = getText();
         char[] chars = null;
@@ -204,55 +225,68 @@
         return chars;
     }
 
+    @Override
     public String getNamespace() {
         return mParser.getNamespace();
     }
 
+    @Override
     public String getName() {
         return mParser.getName();
     }
 
+    @Override
     public String getAttributeNamespace(int index) {
         return mParser.getAttributeNamespace(index);
     }
 
+    @Override
     public String getAttributeName(int index) {
         return mParser.getAttributeName(index);
     }
 
+    @Override
     public String getAttributePrefix(int index) {
         throw new RuntimeException("getAttributePrefix not supported");
     }
 
+    @Override
     public boolean isEmptyElementTag() {
         // XXX Need to detect this.
         return false;
     }
 
+    @Override
     public int getAttributeCount() {
         return mParser.getAttributeCount();
     }
 
+    @Override
     public String getAttributeValue(int index) {
         return mParser.getAttributeValue(index);
     }
 
+    @Override
     public String getAttributeType(int index) {
         return "CDATA";
     }
 
+    @Override
     public boolean isAttributeDefault(int index) {
         return false;
     }
 
+    @Override
     public int nextToken() throws XmlPullParserException, IOException {
         return next();
     }
 
+    @Override
     public String getAttributeValue(String namespace, String name) {
         return mParser.getAttributeValue(namespace, name);
     }
 
+    @Override
     public int next() throws XmlPullParserException, IOException {
         if (!mStarted) {
             mStarted = true;
@@ -313,6 +347,7 @@
         return "????";
     }
 
+    @Override
     public void require(int type, String namespace, String name)
             throws XmlPullParserException {
         if (type != getEventType()
@@ -322,6 +357,7 @@
                     + getPositionDescription());
     }
 
+    @Override
     public String nextText() throws XmlPullParserException, IOException {
         if (getEventType() != START_TAG) {
             throw new XmlPullParserException(getPositionDescription()
@@ -348,6 +384,7 @@
         }
     }
 
+    @Override
     public int nextTag() throws XmlPullParserException, IOException {
         int eventType = next();
         if (eventType == TEXT && isWhitespace()) { // skip whitespace
@@ -363,76 +400,94 @@
     // AttributeSet implementation
 
 
+    @Override
     public void close() {
         // pass
     }
 
+    @Override
     public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
         return mAttrib.getAttributeBooleanValue(index, defaultValue);
     }
 
+    @Override
     public boolean getAttributeBooleanValue(String namespace, String attribute,
             boolean defaultValue) {
         return mAttrib.getAttributeBooleanValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public float getAttributeFloatValue(int index, float defaultValue) {
         return mAttrib.getAttributeFloatValue(index, defaultValue);
     }
 
+    @Override
     public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) {
         return mAttrib.getAttributeFloatValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public int getAttributeIntValue(int index, int defaultValue) {
         return mAttrib.getAttributeIntValue(index, defaultValue);
     }
 
+    @Override
     public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
         return mAttrib.getAttributeIntValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public int getAttributeListValue(int index, String[] options, int defaultValue) {
         return mAttrib.getAttributeListValue(index, options, defaultValue);
     }
 
+    @Override
     public int getAttributeListValue(String namespace, String attribute,
             String[] options, int defaultValue) {
         return mAttrib.getAttributeListValue(namespace, attribute, options, defaultValue);
     }
 
+    @Override
     public int getAttributeNameResource(int index) {
         return mAttrib.getAttributeNameResource(index);
     }
 
+    @Override
     public int getAttributeResourceValue(int index, int defaultValue) {
         return mAttrib.getAttributeResourceValue(index, defaultValue);
     }
 
+    @Override
     public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
         return mAttrib.getAttributeResourceValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public int getAttributeUnsignedIntValue(int index, int defaultValue) {
         return mAttrib.getAttributeUnsignedIntValue(index, defaultValue);
     }
 
+    @Override
     public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) {
         return mAttrib.getAttributeUnsignedIntValue(namespace, attribute, defaultValue);
     }
 
+    @Override
     public String getClassAttribute() {
         return mAttrib.getClassAttribute();
     }
 
+    @Override
     public String getIdAttribute() {
         return mAttrib.getIdAttribute();
     }
 
+    @Override
     public int getIdAttributeResourceValue(int defaultValue) {
         return mAttrib.getIdAttributeResourceValue(defaultValue);
     }
 
+    @Override
     public int getStyleAttribute() {
         return mAttrib.getStyleAttribute();
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 72ed351..1817ab5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -132,7 +132,7 @@
                 if (bitmap != null) {
                     BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(),
                             bitmap);
-                    imageView.setBackgroundDrawable(drawable);
+                    imageView.setImageDrawable(drawable);
                 }
             }
         }
@@ -145,6 +145,14 @@
         }
     }
 
+    protected void loadIconById(int id, String iconReference) {
+        ResourceValue value = getResourceValue(iconReference);
+        if (value != null) {
+            loadIconById(id, value);
+        }
+    }
+
+
     protected Drawable loadIcon(int index, ResourceType type, String name) {
         BridgeContext bridgeContext = (BridgeContext) mContext;
         RenderResources res = bridgeContext.getRenderResources();
@@ -162,34 +170,64 @@
         if (child instanceof ImageView) {
             ImageView imageView = (ImageView) child;
 
-            Drawable drawable = ResourceHelper.getDrawable(
-                    value, (BridgeContext) mContext);
-            if (drawable != null) {
-                imageView.setBackgroundDrawable(drawable);
-            }
-
-            return drawable;
+            return loadIcon(imageView, value);
         }
 
         return null;
     }
 
+    private Drawable loadIconById(int id, ResourceValue value) {
+        View child = findViewById(id);
+        if (child instanceof ImageView) {
+            ImageView imageView = (ImageView) child;
+
+            return loadIcon(imageView, value);
+        }
+
+        return null;
+    }
+
+
+    private Drawable loadIcon(ImageView imageView, ResourceValue value) {
+        Drawable drawable = ResourceHelper.getDrawable(value, (BridgeContext) mContext);
+        if (drawable != null) {
+            imageView.setImageDrawable(drawable);
+        }
+
+        return drawable;
+    }
+
     protected TextView setText(int index, String stringReference) {
         View child = getChildAt(index);
         if (child instanceof TextView) {
             TextView textView = (TextView) child;
-            ResourceValue value = getResourceValue(stringReference);
-            if (value != null) {
-                textView.setText(value.getValue());
-            } else {
-                textView.setText(stringReference);
-            }
+            setText(textView, stringReference);
             return textView;
         }
 
         return null;
     }
 
+    protected TextView setTextById(int id, String stringReference) {
+        View child = findViewById(id);
+        if (child instanceof TextView) {
+            TextView textView = (TextView) child;
+            setText(textView, stringReference);
+            return textView;
+        }
+
+        return null;
+    }
+
+    private void setText(TextView textView, String stringReference) {
+        ResourceValue value = getResourceValue(stringReference);
+        if (value != null) {
+            textView.setText(value.getValue());
+        } else {
+            textView.setText(stringReference);
+        }
+    }
+
     protected void setStyle(String themeEntryName) {
 
         BridgeContext bridgeContext = (BridgeContext) mContext;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
index f6edea4..68f5aba 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
@@ -34,7 +34,7 @@
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
         // We do know the order though.
-        loadIcon(0, icon);
+        loadIconById(android.R.id.home, icon);
         mTextView = setText(1, label);
 
         setStyle("actionBarStyle");
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index d5400d7..6840f46 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -33,10 +33,10 @@
 import com.android.ide.common.rendering.api.ResourceReference;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.Result;
-import com.android.ide.common.rendering.api.SessionParams;
-import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.ide.common.rendering.api.Result.Status;
+import com.android.ide.common.rendering.api.SessionParams;
 import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
+import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
@@ -69,8 +69,8 @@
 import android.view.AttachInfo_Accessor;
 import android.view.BridgeInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.widget.AbsListView;
@@ -82,8 +82,8 @@
 import android.widget.ListView;
 import android.widget.QuickContactBadge;
 import android.widget.TabHost;
-import android.widget.TabWidget;
 import android.widget.TabHost.TabSpec;
+import android.widget.TabWidget;
 
 import java.awt.AlphaComposite;
 import java.awt.Color;
@@ -835,6 +835,7 @@
                 previousTransition.addTransitionListener(new TransitionListener() {
                     private int mChangeDisappearingCount = 0;
 
+                    @Override
                     public void startTransition(LayoutTransition transition, ViewGroup container,
                             View view, int transitionType) {
                         if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
@@ -842,6 +843,7 @@
                         }
                     }
 
+                    @Override
                     public void endTransition(LayoutTransition transition, ViewGroup container,
                             View view, int transitionType) {
                         if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
@@ -1227,6 +1229,7 @@
             TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
                     tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
                     .setContent(new TabHost.TabContentFactory() {
+                        @Override
                         public View createTabContent(String tag) {
                             return new LinearLayout(getContext());
                         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
index c9bb424..22570b9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
@@ -74,38 +74,46 @@
         }
     }
 
+    @Override
     public boolean isEnabled(int position) {
         return true;
     }
 
+    @Override
     public int getCount() {
         return mItems.size();
     }
 
+    @Override
     public Object getItem(int position) {
         return mItems.get(position);
     }
 
+    @Override
     public long getItemId(int position) {
         return position;
     }
 
+    @Override
     public int getItemViewType(int position) {
         return mItems.get(position).getType();
     }
 
+    @Override
     public View getView(int position, View convertView, ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
         AdapterItem item = mItems.get(position);
         return getView(item, null /*parentGroup*/, convertView, parent);
     }
 
+    @Override
     public int getViewTypeCount() {
         return mTypes.size();
     }
 
     // ---- SpinnerAdapter
 
+    @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
         // pass
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
index 2c492e3..199e040 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
@@ -99,23 +99,28 @@
 
     // ---- ExpandableListAdapter
 
+    @Override
     public int getGroupCount() {
         return mItems.size();
     }
 
+    @Override
     public int getChildrenCount(int groupPosition) {
         AdapterItem item = mItems.get(groupPosition);
         return item.getChildren().size();
     }
 
+    @Override
     public Object getGroup(int groupPosition) {
         return mItems.get(groupPosition);
     }
 
+    @Override
     public Object getChild(int groupPosition, int childPosition) {
         return getChildItem(groupPosition, childPosition);
     }
 
+    @Override
     public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
             ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
@@ -123,6 +128,7 @@
         return getView(item, null /*parentItem*/, convertView, parent);
     }
 
+    @Override
     public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
             View convertView, ViewGroup parent) {
         // we don't care about recycling here because we never scroll.
@@ -131,48 +137,59 @@
         return getView(item, parentItem, convertView, parent);
     }
 
+    @Override
     public long getGroupId(int groupPosition) {
         return groupPosition;
     }
 
+    @Override
     public long getChildId(int groupPosition, int childPosition) {
         return childPosition;
     }
 
+    @Override
     public long getCombinedGroupId(long groupId) {
         return groupId << 16 | 0x0000FFFF;
     }
 
+    @Override
     public long getCombinedChildId(long groupId, long childId) {
         return groupId << 16 | childId;
     }
 
+    @Override
     public boolean isChildSelectable(int groupPosition, int childPosition) {
         return true;
     }
 
+    @Override
     public void onGroupCollapsed(int groupPosition) {
         // pass
     }
 
+    @Override
     public void onGroupExpanded(int groupPosition) {
         // pass
     }
 
     // ---- HeterogeneousExpandableList
 
+    @Override
     public int getChildType(int groupPosition, int childPosition) {
         return getChildItem(groupPosition, childPosition).getType();
     }
 
+    @Override
     public int getChildTypeCount() {
         return mChildrenTypes.size();
     }
 
+    @Override
     public int getGroupType(int groupPosition) {
         return mItems.get(groupPosition).getType();
     }
 
+    @Override
     public int getGroupTypeCount() {
         return mGroupTypes.size();
     }
diff --git a/tools/layoutlib/create/.settings/README.txt b/tools/layoutlib/create/.settings/README.txt
new file mode 100644
index 0000000..9120b20
--- /dev/null
+++ b/tools/layoutlib/create/.settings/README.txt
@@ -0,0 +1,2 @@
+Copy this in eclipse project as a .settings folder at the root.
+This ensure proper compilation compliance and warning/error levels.
\ No newline at end of file
diff --git a/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs b/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..5381a0e
--- /dev/null
+++ b/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,93 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.nonnull=com.android.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=com.android.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled
+org.eclipse.jdt.core.compiler.annotation.nullable=com.android.annotations.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 70c8a00..4b33474 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -27,6 +27,7 @@
      * Returns the list of class from layoutlib_create to inject in layoutlib.
      * The list can be empty but must not be null.
      */
+    @Override
     public Class<?>[] getInjectedClasses() {
         return INJECTED_CLASSES;
     }
@@ -35,6 +36,7 @@
      * Returns the list of methods to rewrite as delegates.
      * The list can be empty but must not be null.
      */
+    @Override
     public String[] getDelegateMethods() {
         return DELEGATE_METHODS;
     }
@@ -43,6 +45,7 @@
      * Returns the list of classes on which to delegate all native methods.
      * The list can be empty but must not be null.
      */
+    @Override
     public String[] getDelegateClassNatives() {
         return DELEGATE_CLASS_NATIVES;
     }
@@ -54,6 +57,7 @@
      * <p/>
      * This usage is deprecated. Please use method 'delegates' instead.
      */
+    @Override
     public String[] getOverriddenMethods() {
         return OVERRIDDEN_METHODS;
     }
@@ -63,6 +67,7 @@
      * of class to replace followed by the new FQCN.
      * The list can be empty but must not be null.
      */
+    @Override
     public String[] getRenamedClasses() {
         return RENAMED_CLASSES;
     }
@@ -74,6 +79,7 @@
      * the methods to delete.
      * The list can be empty but must not be null.
      */
+    @Override
     public String[] getDeleteReturns() {
         return DELETE_RETURNS;
     }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java
index 627ea17..7d1e4cf 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java
@@ -28,13 +28,14 @@
      * A stub method is being invoked.
      * <p/>
      * Known limitation: caller arguments are not available.
-     *  
+     *
      * @param signature The signature of the method being invoked, composed of the
      *                  binary class name followed by the method descriptor (aka argument
      *                  types). Example: "com/foo/MyClass/InnerClass/printInt(I)V".
      * @param isNative True if the method was a native method.
      * @param caller The calling object. Null for static methods, "this" for instance methods.
      */
+    @Override
     public void onInvokeV(String signature, boolean isNative, Object caller) {
     }
 
@@ -43,6 +44,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return an integer, or a boolean, or a short or a byte.
      */
+    @Override
     public int onInvokeI(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return 0;
@@ -53,6 +55,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return a long.
      */
+    @Override
     public long onInvokeL(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return 0;
@@ -63,6 +66,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return a float.
      */
+    @Override
     public float onInvokeF(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return 0;
@@ -73,6 +77,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return a double.
      */
+    @Override
     public double onInvokeD(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return 0;
@@ -83,6 +88,7 @@
      * @see #onInvokeV(String, boolean, Object)
      * @return an object.
      */
+    @Override
     public Object onInvokeA(String signature, boolean isNative, Object caller) {
         onInvokeV(signature, isNative, caller);
         return null;
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index f4ff389..7b76a5b 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -65,24 +65,29 @@
     public void testClassRenaming() throws IOException, LogAbortException {
 
         ICreateInfo ci = new ICreateInfo() {
+            @Override
             public Class<?>[] getInjectedClasses() {
                 // classes to inject in the final JAR
                 return new Class<?>[0];
             }
 
+            @Override
             public String[] getDelegateMethods() {
                 return new String[0];
             }
 
+            @Override
             public String[] getDelegateClassNatives() {
                 return new String[0];
             }
 
+            @Override
             public String[] getOverriddenMethods() {
                 // methods to force override
                 return new String[0];
             }
 
+            @Override
             public String[] getRenamedClasses() {
                 // classes to rename (so that we can replace them)
                 return new String[] {
@@ -91,6 +96,7 @@
                 };
             }
 
+            @Override
             public String[] getDeleteReturns() {
                  // methods deleted from their return type.
                 return new String[0];
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index bbb74d1..d05e0b8 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -366,17 +366,6 @@
                     handleDriverEvent(eventData);
                 } else if (event == TERMINATING) {
                     /**
-                     * If monitor socket is closed, we have already
-                     * stopped the supplicant, simply exit the monitor thread
-                     */
-                    if (eventData.startsWith(MONITOR_SOCKET_CLOSED_STR)) {
-                        if (false) {
-                            Log.d(TAG, "Monitor socket is closed, exiting thread");
-                        }
-                        break;
-                    }
-
-                    /**
                      * Close the supplicant connection if we see
                      * too many recv errors
                      */
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 48a785c..e3dd3a6 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -39,6 +39,8 @@
  */
 public class WifiNative {
 
+    private static final boolean DBG = false;
+    private final String mTAG;
     private static final int DEFAULT_GROUP_OWNER_INTENT = 7;
 
     static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0;
@@ -53,9 +55,7 @@
 
     public native static boolean unloadDriver();
 
-    public native static boolean startSupplicant();
-
-    public native static boolean startP2pSupplicant();
+    public native static boolean startSupplicant(boolean p2pSupported);
 
     /* Sends a kill signal to supplicant. To be used when we have lost connection
        or when the supplicant is hung */
@@ -79,6 +79,7 @@
 
     public WifiNative(String iface) {
         mInterface = iface;
+        mTAG = "WifiNative-" + iface;
     }
 
     public boolean connectToSupplicant() {
@@ -94,14 +95,17 @@
     }
 
     private boolean doBooleanCommand(String command) {
+        if (DBG) Log.d(mTAG, "doBoolean: " + command);
         return doBooleanCommand(mInterface, command);
     }
 
     private int doIntCommand(String command) {
+        if (DBG) Log.d(mTAG, "doInt: " + command);
         return doIntCommand(mInterface, command);
     }
 
     private String doStringCommand(String command) {
+        if (DBG) Log.d(mTAG, "doString: " + command);
         return doStringCommand(mInterface, command);
     }
 
@@ -437,6 +441,10 @@
         return doBooleanCommand("P2P_FIND " + timeout);
     }
 
+    public boolean p2pStopFind() {
+       return doBooleanCommand("P2P_STOP_FIND");
+    }
+
     public boolean p2pListen() {
         return doBooleanCommand("P2P_LISTEN");
     }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 8c9e472..0134456 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -45,6 +45,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.DhcpInfo;
 import android.net.DhcpInfoInternal;
@@ -118,6 +119,8 @@
     private INetworkManagementService mNwService;
     private ConnectivityManager mCm;
 
+    private final boolean mP2pSupported;
+
     /* Scan results handling */
     private List<ScanResult> mScanResults;
     private static final Pattern scanResultPattern = Pattern.compile("\t+");
@@ -361,9 +364,9 @@
     /* Reset the WPS state machine */
     static final int CMD_RESET_WPS_STATE                  = BASE + 122;
 
-    /* Interaction with WifiP2pService */
-    public static final int WIFI_ENABLE_PENDING           = BASE + 131;
-    public static final int P2P_ENABLE_PROCEED            = BASE + 132;
+    /* P2p commands */
+    public static final int CMD_ENABLE_P2P                = BASE + 131;
+    public static final int CMD_DISABLE_P2P               = BASE + 132;
 
     private static final int CONNECT_MODE   = 1;
     private static final int SCAN_ONLY_MODE = 2;
@@ -482,9 +485,6 @@
     /* Waiting for untether confirmation to stop soft Ap */
     private State mSoftApStoppingState = new SoftApStoppingState();
 
-    /* Wait till p2p is disabled */
-    private State mWaitForP2pDisableState = new WaitForP2pDisableState();
-
     private class TetherStateChange {
         ArrayList<String> available;
         ArrayList<String> active;
@@ -556,6 +556,9 @@
         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
         mNwService = INetworkManagementService.Stub.asInterface(b);
 
+        mP2pSupported = mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_WIFI_DIRECT);
+
         mWifiNative = new WifiNative(mInterfaceName);
         mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
         mWifiMonitor = new WifiMonitor(this, mWifiNative);
@@ -639,7 +642,6 @@
                 addState(mTetheringState, mSoftApStartedState);
                 addState(mTetheredState, mSoftApStartedState);
             addState(mSoftApStoppingState, mDefaultState);
-            addState(mWaitForP2pDisableState, mDefaultState);
 
         setInitialState(mInitialState);
 
@@ -1629,6 +1631,10 @@
          * stop DHCP
          */
         if (mDhcpStateMachine != null) {
+            /* In case we were in middle of DHCP operation
+               restore back powermode */
+            handlePostDhcpSetup();
+
             mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
             mDhcpStateMachine.quit();
             mDhcpStateMachine = null;
@@ -1892,11 +1898,6 @@
                     mReplyChannel.replyToMessage(message, WifiManager.CMD_WPS_COMPLETED,
                                 new WpsResult(Status.FAILURE));
                     break;
-                case WifiP2pService.P2P_ENABLE_PENDING:
-                    // turn off wifi and defer to be handled in DriverUnloadedState
-                    setWifiEnabled(false);
-                    deferMessage(message);
-                    break;
                 default:
                     loge("Error! unhandled message" + message);
                     break;
@@ -2056,7 +2057,7 @@
                         loge("Unable to change interface settings: " + ie);
                     }
 
-                    if(mWifiNative.startSupplicant()) {
+                    if(mWifiNative.startSupplicant(mP2pSupported)) {
                         if (DBG) log("Supplicant start successful");
                         mWifiMonitor.startMonitoring();
                         transitionTo(mSupplicantStartingState);
@@ -2168,11 +2169,7 @@
             if (DBG) log(getName() + message.toString() + "\n");
             switch (message.what) {
                 case CMD_LOAD_DRIVER:
-                    mWifiP2pChannel.sendMessage(WIFI_ENABLE_PENDING);
-                    transitionTo(mWaitForP2pDisableState);
-                    break;
-                case WifiP2pService.P2P_ENABLE_PENDING:
-                    mReplyChannel.replyToMessage(message, P2P_ENABLE_PROCEED);
+                    transitionTo(mDriverLoadingState);
                     break;
                 default:
                     return NOT_HANDLED;
@@ -2391,6 +2388,10 @@
         public void enter() {
             if (DBG) log(getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+            /* Send any reset commands to supplicant before shutting it down */
+            handleNetworkDisconnect();
+
             if (DBG) log("stopping supplicant");
             if (!mWifiNative.stopSupplicant()) {
                 loge("Failed to stop supplicant");
@@ -2401,7 +2402,6 @@
                     ++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
 
             mNetworkInfo.setIsAvailable(false);
-            handleNetworkDisconnect();
             setWifiState(WIFI_STATE_DISABLING);
             sendSupplicantConnectionChangedBroadcast(false);
             mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
@@ -2549,13 +2549,15 @@
                 mWifiNative.status();
                 transitionTo(mDisconnectedState);
             }
+
+            if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P);
         }
         @Override
         public boolean processMessage(Message message) {
             if (DBG) log(getName() + message.toString() + "\n");
             boolean eventLoggingEnabled = true;
             switch(message.what) {
-                case CMD_SET_SCAN_TYPE:
+               case CMD_SET_SCAN_TYPE:
                     mSetScanActive = (message.arg1 == SCAN_ACTIVE);
                     mWifiNative.setScanMode(mSetScanActive);
                     break;
@@ -2668,6 +2670,8 @@
             mIsRunning = false;
             updateBatteryWorkSource(null);
             mScanResults = null;
+
+            if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P);
         }
     }
 
@@ -3341,7 +3345,6 @@
                 case CMD_START_PACKET_FILTERING:
                 case CMD_STOP_PACKET_FILTERING:
                 case CMD_TETHER_STATE_CHANGE:
-                case WifiP2pService.P2P_ENABLE_PENDING:
                     deferMessage(message);
                     break;
                 case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
@@ -3405,55 +3408,6 @@
                         transitionTo(mTetheringState);
                     }
                     break;
-                case WifiP2pService.P2P_ENABLE_PENDING:
-                    // turn of soft Ap and defer to be handled in DriverUnloadedState
-                    setWifiApEnabled(null, false);
-                    deferMessage(message);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
-            return HANDLED;
-        }
-    }
-
-    class WaitForP2pDisableState extends State {
-        private int mSavedArg;
-        @Override
-        public void enter() {
-            if (DBG) log(getName() + "\n");
-            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
-
-            //Preserve the argument arg1 that has information used in DriverLoadingState
-            mSavedArg = getCurrentMessage().arg1;
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) log(getName() + message.toString() + "\n");
-            switch(message.what) {
-                case WifiP2pService.WIFI_ENABLE_PROCEED:
-                    //restore argument from original message (CMD_LOAD_DRIVER)
-                    message.arg1 = mSavedArg;
-                    transitionTo(mDriverLoadingState);
-                    break;
-                case CMD_LOAD_DRIVER:
-                case CMD_UNLOAD_DRIVER:
-                case CMD_START_SUPPLICANT:
-                case CMD_STOP_SUPPLICANT:
-                case CMD_START_AP:
-                case CMD_STOP_AP:
-                case CMD_START_DRIVER:
-                case CMD_STOP_DRIVER:
-                case CMD_SET_SCAN_MODE:
-                case CMD_SET_SCAN_TYPE:
-                case CMD_SET_HIGH_PERF_MODE:
-                case CMD_SET_COUNTRY_CODE:
-                case CMD_SET_FREQUENCY_BAND:
-                case CMD_START_PACKET_FILTERING:
-                case CMD_STOP_PACKET_FILTERING:
-                    deferMessage(message);
-                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -3503,7 +3457,6 @@
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
                 case CMD_STOP_PACKET_FILTERING:
-                case WifiP2pService.P2P_ENABLE_PENDING:
                     deferMessage(message);
                     break;
                 default:
@@ -3599,7 +3552,6 @@
                 case CMD_SET_FREQUENCY_BAND:
                 case CMD_START_PACKET_FILTERING:
                 case CMD_STOP_PACKET_FILTERING:
-                case WifiP2pService.P2P_ENABLE_PENDING:
                     deferMessage(message);
                     break;
                 default:
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 7471a2d..b0cde64 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -301,7 +301,8 @@
     private String trimQuotes(String str) {
         str = str.trim();
         if (str.startsWith("'") && str.endsWith("'")) {
-            return str.substring(1, str.length()-1);
+            if (str.length() <= 2) return "";
+            else return str.substring(1, str.length()-1);
         }
         return str;
     }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 9205300..4fd0a57 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -199,68 +199,61 @@
     private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER;
 
     /** @hide */
-    public static final int ENABLE_P2P                              = BASE + 1;
+    public static final int DISCOVER_PEERS                          = BASE + 1;
     /** @hide */
-    public static final int ENABLE_P2P_FAILED                       = BASE + 2;
+    public static final int DISCOVER_PEERS_FAILED                   = BASE + 2;
     /** @hide */
-    public static final int ENABLE_P2P_SUCCEEDED                    = BASE + 3;
+    public static final int DISCOVER_PEERS_SUCCEEDED                = BASE + 3;
 
     /** @hide */
-    public static final int DISABLE_P2P                             = BASE + 4;
+    public static final int STOP_DISCOVERY                          = BASE + 4;
     /** @hide */
-    public static final int DISABLE_P2P_FAILED                      = BASE + 5;
+    public static final int STOP_DISCOVERY_FAILED                   = BASE + 5;
     /** @hide */
-    public static final int DISABLE_P2P_SUCCEEDED                   = BASE + 6;
+    public static final int STOP_DISCOVERY_SUCCEEDED                = BASE + 6;
 
     /** @hide */
-    public static final int DISCOVER_PEERS                          = BASE + 7;
+    public static final int CONNECT                                 = BASE + 7;
     /** @hide */
-    public static final int DISCOVER_PEERS_FAILED                   = BASE + 8;
+    public static final int CONNECT_FAILED                          = BASE + 8;
     /** @hide */
-    public static final int DISCOVER_PEERS_SUCCEEDED                = BASE + 9;
+    public static final int CONNECT_SUCCEEDED                       = BASE + 9;
 
     /** @hide */
-    public static final int CONNECT                                 = BASE + 10;
+    public static final int CANCEL_CONNECT                          = BASE + 10;
     /** @hide */
-    public static final int CONNECT_FAILED                          = BASE + 11;
+    public static final int CANCEL_CONNECT_FAILED                   = BASE + 11;
     /** @hide */
-    public static final int CONNECT_SUCCEEDED                       = BASE + 12;
+    public static final int CANCEL_CONNECT_SUCCEEDED                = BASE + 12;
 
     /** @hide */
-    public static final int CANCEL_CONNECT                          = BASE + 13;
+    public static final int CREATE_GROUP                            = BASE + 13;
     /** @hide */
-    public static final int CANCEL_CONNECT_FAILED                   = BASE + 14;
+    public static final int CREATE_GROUP_FAILED                     = BASE + 14;
     /** @hide */
-    public static final int CANCEL_CONNECT_SUCCEEDED                = BASE + 15;
+    public static final int CREATE_GROUP_SUCCEEDED                  = BASE + 15;
 
     /** @hide */
-    public static final int CREATE_GROUP                            = BASE + 16;
+    public static final int REMOVE_GROUP                            = BASE + 16;
     /** @hide */
-    public static final int CREATE_GROUP_FAILED                     = BASE + 17;
+    public static final int REMOVE_GROUP_FAILED                     = BASE + 17;
     /** @hide */
-    public static final int CREATE_GROUP_SUCCEEDED                  = BASE + 18;
+    public static final int REMOVE_GROUP_SUCCEEDED                  = BASE + 18;
 
     /** @hide */
-    public static final int REMOVE_GROUP                            = BASE + 19;
+    public static final int REQUEST_PEERS                           = BASE + 19;
     /** @hide */
-    public static final int REMOVE_GROUP_FAILED                     = BASE + 20;
-    /** @hide */
-    public static final int REMOVE_GROUP_SUCCEEDED                  = BASE + 21;
+    public static final int RESPONSE_PEERS                          = BASE + 20;
 
     /** @hide */
-    public static final int REQUEST_PEERS                           = BASE + 22;
+    public static final int REQUEST_CONNECTION_INFO                 = BASE + 21;
     /** @hide */
-    public static final int RESPONSE_PEERS                          = BASE + 23;
+    public static final int RESPONSE_CONNECTION_INFO                = BASE + 22;
 
     /** @hide */
-    public static final int REQUEST_CONNECTION_INFO                 = BASE + 24;
+    public static final int REQUEST_GROUP_INFO                      = BASE + 23;
     /** @hide */
-    public static final int RESPONSE_CONNECTION_INFO                = BASE + 25;
-
-    /** @hide */
-    public static final int REQUEST_GROUP_INFO                      = BASE + 26;
-    /** @hide */
-    public static final int RESPONSE_GROUP_INFO                     = BASE + 27;
+    public static final int RESPONSE_GROUP_INFO                     = BASE + 24;
 
     /**
      * Create a new WifiP2pManager instance. Applications use
@@ -376,6 +369,7 @@
                         break;
                     /* ActionListeners grouped together */
                     case WifiP2pManager.DISCOVER_PEERS_FAILED:
+                    case WifiP2pManager.STOP_DISCOVERY_FAILED:
                     case WifiP2pManager.CONNECT_FAILED:
                     case WifiP2pManager.CANCEL_CONNECT_FAILED:
                     case WifiP2pManager.CREATE_GROUP_FAILED:
@@ -386,6 +380,7 @@
                         break;
                     /* ActionListeners grouped together */
                     case WifiP2pManager.DISCOVER_PEERS_SUCCEEDED:
+                    case WifiP2pManager.STOP_DISCOVERY_SUCCEEDED:
                     case WifiP2pManager.CONNECT_SUCCEEDED:
                     case WifiP2pManager.CANCEL_CONNECT_SUCCEEDED:
                     case WifiP2pManager.CREATE_GROUP_SUCCEEDED:
@@ -459,26 +454,6 @@
     }
 
     /**
-     * Sends in a request to the system to enable p2p. This will pop up a dialog
-     * to the user and upon authorization will enable p2p.
-     * @hide
-     */
-    public void enableP2p(Channel c) {
-        if (c == null) return;
-        c.mAsyncChannel.sendMessage(ENABLE_P2P);
-    }
-
-    /**
-     * Sends in a request to the system to disable p2p. This will pop up a dialog
-     * to the user and upon authorization will enable p2p.
-     * @hide
-     */
-    public void disableP2p(Channel c) {
-        if (c == null) return;
-        c.mAsyncChannel.sendMessage(DISABLE_P2P);
-    }
-
-    /**
      * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers
      * for the purpose of establishing a connection.
      *
@@ -503,6 +478,16 @@
     }
 
     /**
+     * TODO: Add more documentation before opening up
+     * Cancel peer discovery
+     * @hide
+     */
+    public void stopPeerDiscovery(Channel c, ActionListener listener) {
+        if (c == null) return;
+        c.mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, c.putListener(listener));
+    }
+
+    /**
      * Start a p2p connection to a device with the specified configuration.
      *
      * <p> The function call immediately returns after sending a connection request
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 69cbb5c..5b0e424 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -49,6 +49,7 @@
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.Messenger;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.provider.Settings;
@@ -84,7 +85,7 @@
  */
 public class WifiP2pService extends IWifiP2pManager.Stub {
     private static final String TAG = "WifiP2pService";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final String NETWORKTYPE = "WIFI_P2P";
 
     private Context mContext;
@@ -94,11 +95,6 @@
     INetworkManagementService mNwService;
     private DhcpStateMachine mDhcpStateMachine;
 
-    //Tracked to notify the user about wifi client/hotspot being shut down
-    //during p2p bring up
-    private int mWifiState = WifiManager.WIFI_STATE_DISABLED;
-    private int mWifiApState = WifiManager.WIFI_AP_STATE_DISABLED;
-
     private P2pStateMachine mP2pStateMachine;
     private AsyncChannel mReplyChannel = new AsyncChannel();
     private AsyncChannel mWifiChannel;
@@ -110,6 +106,9 @@
     private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000;
     private static int mGroupCreatingTimeoutIndex = 0;
 
+    /* Set a two minute discover timeout to avoid STA scans from being blocked */
+    private static final int DISCOVER_TIMEOUT_S = 120;
+
     /**
      * Delay between restarts upon failure to setup connection with supplicant
      */
@@ -124,28 +123,13 @@
 
     private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE;
 
-    /* Message sent to WifiStateMachine to indicate p2p enable is pending */
-    public static final int P2P_ENABLE_PENDING              =   BASE + 1;
-    /* Message sent to WifiStateMachine to indicate Wi-Fi client/hotspot operation can proceed */
-    public static final int WIFI_ENABLE_PROCEED             =   BASE + 2;
-
     /* Delayed message to timeout group creation */
-    public static final int GROUP_CREATING_TIMED_OUT        =   BASE + 3;
-
-    /* User accepted to disable Wi-Fi in order to enable p2p */
-    private static final int WIFI_DISABLE_USER_ACCEPT       =   BASE + 4;
-    /* User rejected to disable Wi-Fi in order to enable p2p */
-    private static final int WIFI_DISABLE_USER_REJECT       =   BASE + 5;
+    public static final int GROUP_CREATING_TIMED_OUT        =   BASE + 1;
 
     /* User accepted a peer request */
-    private static final int PEER_CONNECTION_USER_ACCEPT    =   BASE + 6;
+    private static final int PEER_CONNECTION_USER_ACCEPT    =   BASE + 2;
     /* User rejected a peer request */
-    private static final int PEER_CONNECTION_USER_REJECT    =   BASE + 7;
-
-    /* Airplane mode changed */
-    private static final int AIRPLANE_MODE_CHANGED          =   BASE + 8;
-    /* Emergency callback mode */
-    private static final int EMERGENCY_CALLBACK_MODE        =   BASE + 9;
+    private static final int PEER_CONNECTION_USER_REJECT    =   BASE + 3;
 
     private final boolean mP2pSupported;
 
@@ -166,7 +150,7 @@
     public WifiP2pService(Context context) {
         mContext = context;
 
-        //STOPSHIP: fix this
+        //STOPSHIP: get this from native side
         mInterface = "p2p0";
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
 
@@ -179,15 +163,6 @@
 
         mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported);
         mP2pStateMachine.start();
-
-        // broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
-        filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
-        mContext.registerReceiver(new WifiStateReceiver(), filter);
-
     }
 
     public void connectivityServiceReady() {
@@ -195,26 +170,6 @@
         mNwService = INetworkManagementService.Stub.asInterface(b);
     }
 
-    private class WifiStateReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
-                        WifiManager.WIFI_STATE_DISABLED);
-            } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
-                mWifiApState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
-                        WifiManager.WIFI_AP_STATE_DISABLED);
-            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
-                mP2pStateMachine.sendMessage(AIRPLANE_MODE_CHANGED);
-            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
-                if (intent.getBooleanExtra("phoneinECMState", false) == true) {
-                    mP2pStateMachine.sendMessage(EMERGENCY_CALLBACK_MODE);
-                }
-            }
-        }
-    }
-
     private void enforceAccessPermission() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
                 "WifiP2pService");
@@ -264,8 +219,6 @@
         private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState();
         private P2pDisablingState mP2pDisablingState = new P2pDisablingState();
         private P2pDisabledState mP2pDisabledState = new P2pDisabledState();
-        private WaitForUserActionState mWaitForUserActionState = new WaitForUserActionState();
-        private WaitForWifiDisableState mWaitForWifiDisableState = new WaitForWifiDisableState();
         private P2pEnablingState mP2pEnablingState = new P2pEnablingState();
         private P2pEnabledState mP2pEnabledState = new P2pEnabledState();
         // Inactive is when p2p is enabled with no connectivity
@@ -299,8 +252,6 @@
                 addState(mP2pNotSupportedState, mDefaultState);
                 addState(mP2pDisablingState, mDefaultState);
                 addState(mP2pDisabledState, mDefaultState);
-                    addState(mWaitForUserActionState, mP2pDisabledState);
-                    addState(mWaitForWifiDisableState, mP2pDisabledState);
                 addState(mP2pEnablingState, mDefaultState);
                 addState(mP2pEnabledState, mDefaultState);
                     addState(mInactiveState, mP2pEnabledState);
@@ -346,23 +297,14 @@
                     AsyncChannel ac = new AsyncChannel();
                     ac.connect(mContext, getHandler(), message.replyTo);
                     break;
-                case WifiStateMachine.WIFI_ENABLE_PENDING:
-                    // Disable p2p operation before we can respond
-                    sendMessage(WifiP2pManager.DISABLE_P2P);
-                    deferMessage(message);
-                    break;
-                case WifiP2pManager.ENABLE_P2P:
-                    replyToMessage(message, WifiP2pManager.ENABLE_P2P_FAILED,
-                            WifiP2pManager.BUSY);
-                    break;
-                case WifiP2pManager.DISABLE_P2P:
-                    replyToMessage(message, WifiP2pManager.DISABLE_P2P_FAILED,
-                            WifiP2pManager.BUSY);
-                    break;
                 case WifiP2pManager.DISCOVER_PEERS:
                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
                             WifiP2pManager.BUSY);
                     break;
+                case WifiP2pManager.STOP_DISCOVERY:
+                    replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
+                            WifiP2pManager.BUSY);
+                    break;
                 case WifiP2pManager.CONNECT:
                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
                             WifiP2pManager.BUSY);
@@ -388,16 +330,14 @@
                 case WifiP2pManager.REQUEST_GROUP_INFO:
                     replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup);
                     break;
-                case AIRPLANE_MODE_CHANGED:
-                    if (isAirplaneModeOn()) sendMessage(WifiP2pManager.DISABLE_P2P);
-                    break;
-                case EMERGENCY_CALLBACK_MODE:
-                    sendMessage(WifiP2pManager.DISABLE_P2P);
-                    break;
                     // Ignore
                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
-                case WIFI_DISABLE_USER_ACCEPT:
-                case WIFI_DISABLE_USER_REJECT:
+                case WifiMonitor.SCAN_RESULTS_EVENT:
+                case WifiMonitor.SUP_CONNECTION_EVENT:
+                case WifiMonitor.SUP_DISCONNECTION_EVENT:
+                case WifiMonitor.NETWORK_CONNECTION_EVENT:
+                case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
+                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
                 case PEER_CONNECTION_USER_ACCEPT:
                 case PEER_CONNECTION_USER_REJECT:
                 case GROUP_CREATING_TIMED_OUT:
@@ -414,22 +354,14 @@
         @Override
         public boolean processMessage(Message message) {
             switch (message.what) {
-                // Allow Wi-Fi to proceed
-                case WifiStateMachine.WIFI_ENABLE_PENDING:
-                    replyToMessage(message, WIFI_ENABLE_PROCEED);
-                    break;
-                case WifiP2pManager.ENABLE_P2P:
-                    replyToMessage(message, WifiP2pManager.ENABLE_P2P_FAILED,
-                            WifiP2pManager.P2P_UNSUPPORTED);
-                    break;
-                case WifiP2pManager.DISABLE_P2P:
-                    replyToMessage(message, WifiP2pManager.DISABLE_P2P_FAILED,
-                            WifiP2pManager.P2P_UNSUPPORTED);
-                    break;
-                case WifiP2pManager.DISCOVER_PEERS:
+               case WifiP2pManager.DISCOVER_PEERS:
                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
                     break;
+                case WifiP2pManager.STOP_DISCOVERY:
+                    replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
+                            WifiP2pManager.P2P_UNSUPPORTED);
+                    break;
                 case WifiP2pManager.CONNECT:
                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
@@ -438,7 +370,7 @@
                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
                     break;
-                case WifiP2pManager.CREATE_GROUP:
+               case WifiP2pManager.CREATE_GROUP:
                     replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
                             WifiP2pManager.P2P_UNSUPPORTED);
                     break;
@@ -455,26 +387,15 @@
 
     class P2pDisablingState extends State {
         @Override
-        public void enter() {
-            if (DBG) logd(getName());
-            logd("stopping supplicant");
-            if (!mWifiNative.stopSupplicant()) {
-                loge("Failed to stop supplicant, issue kill");
-                mWifiNative.killSupplicant();
-            }
-        }
-
-        @Override
         public boolean processMessage(Message message) {
             if (DBG) logd(getName() + message.toString());
             switch (message.what) {
                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
-                    logd("Supplicant connection lost");
-                    mWifiNative.closeSupplicantConnection();
+                    if (DBG) logd("p2p socket connection lost");
                     transitionTo(mP2pDisabledState);
                     break;
-                case WifiP2pManager.ENABLE_P2P:
-                case WifiP2pManager.DISABLE_P2P:
+                case WifiStateMachine.CMD_ENABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P:
                     deferMessage(message);
                     break;
                 default:
@@ -484,7 +405,6 @@
         }
     }
 
-
     class P2pDisabledState extends State {
        @Override
         public void enter() {
@@ -495,118 +415,19 @@
         public boolean processMessage(Message message) {
             if (DBG) logd(getName() + message.toString());
             switch (message.what) {
-                case WifiP2pManager.ENABLE_P2P:
-                    OnClickListener listener = new OnClickListener() {
-                        @Override
-                        public void onClick(DialogInterface dialog, int which) {
-                            if (which == DialogInterface.BUTTON_POSITIVE) {
-                                sendMessage(WIFI_DISABLE_USER_ACCEPT);
-                            } else {
-                                sendMessage(WIFI_DISABLE_USER_REJECT);
-                            }
-                        }
-                    };
-
-                    // Show a user request dialog if we know Wi-Fi client/hotspot is in operation
-                    if (mWifiState != WifiManager.WIFI_STATE_DISABLED ||
-                            mWifiApState != WifiManager.WIFI_AP_STATE_DISABLED) {
-                        Resources r = Resources.getSystem();
-                        AlertDialog dialog = new AlertDialog.Builder(mContext)
-                            .setTitle(r.getString(R.string.wifi_p2p_dialog_title))
-                            .setMessage(r.getString(R.string.wifi_p2p_turnon_message))
-                            .setPositiveButton(r.getString(R.string.ok), listener)
-                            .setNegativeButton(r.getString(R.string.cancel), listener)
-                            .create();
-                        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-                        dialog.show();
-                        transitionTo(mWaitForUserActionState);
-                    } else {
-                        mWifiChannel.sendMessage(P2P_ENABLE_PENDING);
-                        transitionTo(mWaitForWifiDisableState);
-                    }
-                    replyToMessage(message, WifiP2pManager.ENABLE_P2P_SUCCEEDED);
-                    break;
-                case WifiP2pManager.DISABLE_P2P:
-                    replyToMessage(message, WifiP2pManager.DISABLE_P2P_SUCCEEDED);
-                    break;
-                case WifiStateMachine.WIFI_ENABLE_PENDING:
-                    replyToMessage(message, WIFI_ENABLE_PROCEED);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-    }
-
-    class WaitForUserActionState extends State {
-        @Override
-        public void enter() {
-            if (DBG) logd(getName());
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) logd(getName() + message.toString());
-            switch (message.what) {
-                case WIFI_DISABLE_USER_ACCEPT:
-                    mWifiChannel.sendMessage(P2P_ENABLE_PENDING);
-                    transitionTo(mWaitForWifiDisableState);
-                    break;
-                case WIFI_DISABLE_USER_REJECT:
-                    logd("User rejected enabling p2p");
-                    sendP2pStateChangedBroadcast(false);
-                    transitionTo(mP2pDisabledState);
-                    break;
-                case WifiP2pManager.ENABLE_P2P:
-                case WifiP2pManager.DISABLE_P2P:
-                    deferMessage(message);
-                    break;
-                default:
-                    return NOT_HANDLED;
-            }
-            return HANDLED;
-        }
-    }
-
-    class WaitForWifiDisableState extends State {
-        @Override
-        public void enter() {
-            if (DBG) logd(getName());
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) logd(getName() + message.toString());
-            switch (message.what) {
-                case WifiStateMachine.P2P_ENABLE_PROCEED:
+                case WifiStateMachine.CMD_ENABLE_P2P:
                     try {
-                        mNwService.wifiFirmwareReload(mInterface, "P2P");
-                    } catch (Exception e) {
-                        loge("Failed to reload p2p firmware " + e);
-                        // continue
+                        mNwService.setInterfaceUp(mInterface);
+                    } catch (RemoteException re) {
+                        loge("Unable to change interface settings: " + re);
+                    } catch (IllegalStateException ie) {
+                        loge("Unable to change interface settings: " + ie);
                     }
-
-                    //A runtime crash can leave the interface up and
-                    //this affects p2p when supplicant starts up.
-                    //Ensure interface is down before a supplicant start.
-                    try {
-                        mNwService.setInterfaceDown(mInterface);
-                    } catch (Exception e) {
-                        if (DBG) Slog.w(TAG, "Unable to bring down wlan interface: " + e);
-                    }
-
-                    if (mWifiNative.startP2pSupplicant()) {
-                        mWifiMonitor.startMonitoring();
-                        transitionTo(mP2pEnablingState);
-                    } else {
-                        notifyP2pEnableFailure();
-                        transitionTo(mP2pDisabledState);
-                    }
+                    mWifiMonitor.startMonitoring();
+                    transitionTo(mP2pEnablingState);
                     break;
-                case WifiP2pManager.ENABLE_P2P:
-                case WifiP2pManager.DISABLE_P2P:
-                    deferMessage(message);
+                case WifiStateMachine.CMD_DISABLE_P2P:
+                    //Nothing to do
                     break;
                 default:
                     return NOT_HANDLED;
@@ -626,22 +447,15 @@
             if (DBG) logd(getName() + message.toString());
             switch (message.what) {
                 case WifiMonitor.SUP_CONNECTION_EVENT:
-                    logd("P2p start successful");
+                    if (DBG) logd("P2p socket connection successful");
                     transitionTo(mInactiveState);
                     break;
                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
-                    if (++mP2pRestartCount <= P2P_RESTART_TRIES) {
-                        loge("Failed to start p2p, retry");
-                        mWifiNative.killSupplicant();
-                        sendMessageDelayed(WifiP2pManager.ENABLE_P2P, P2P_RESTART_INTERVAL_MSECS);
-                    } else {
-                        loge("Failed " + mP2pRestartCount + " times to start p2p, quit ");
-                        mP2pRestartCount = 0;
-                    }
+                    loge("P2p socket connection failed");
                     transitionTo(mP2pDisabledState);
                     break;
-                case WifiP2pManager.ENABLE_P2P:
-                case WifiP2pManager.DISABLE_P2P:
+                case WifiStateMachine.CMD_ENABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P:
                     deferMessage(message);
                     break;
                 default:
@@ -658,30 +472,36 @@
             sendP2pStateChangedBroadcast(true);
             mNetworkInfo.setIsAvailable(true);
             initializeP2pSettings();
-            showNotification();
         }
 
         @Override
         public boolean processMessage(Message message) {
             if (DBG) logd(getName() + message.toString());
             switch (message.what) {
-                case WifiP2pManager.ENABLE_P2P:
-                    replyToMessage(message, WifiP2pManager.ENABLE_P2P_SUCCEEDED);
+                case WifiStateMachine.CMD_ENABLE_P2P:
+                    //Nothing to do
                     break;
-                case WifiP2pManager.DISABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P:
                     if (mPeers.clear()) sendP2pPeersChangedBroadcast();
-                    replyToMessage(message, WifiP2pManager.DISABLE_P2P_SUCCEEDED);
+                    mWifiNative.closeSupplicantConnection();
                     transitionTo(mP2pDisablingState);
                     break;
                 case WifiP2pManager.DISCOVER_PEERS:
-                    int timeout = message.arg1;
-                    if (mWifiNative.p2pFind(timeout)) {
+                    if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
                         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
                     } else {
                         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
                                 WifiP2pManager.ERROR);
                     }
                     break;
+                case WifiP2pManager.STOP_DISCOVERY:
+                    if (mWifiNative.p2pStopFind()) {
+                        replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
+                                WifiP2pManager.ERROR);
+                    }
+                    break;
                 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
                     if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
@@ -692,15 +512,7 @@
                     device = (WifiP2pDevice) message.obj;
                     if (mPeers.remove(device)) sendP2pPeersChangedBroadcast();
                     break;
-               case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant died */
-                    loge("Connection lost, restart p2p");
-                    mWifiNative.killSupplicant();
-                    mWifiNative.closeSupplicantConnection();
-                    if (mPeers.clear()) sendP2pPeersChangedBroadcast();
-                    transitionTo(mP2pDisabledState);
-                    sendMessageDelayed(WifiP2pManager.ENABLE_P2P, P2P_RESTART_INTERVAL_MSECS);
-                    break;
-                default:
+               default:
                     return NOT_HANDLED;
             }
             return HANDLED;
@@ -710,7 +522,6 @@
         public void exit() {
             sendP2pStateChangedBroadcast(false);
             mNetworkInfo.setIsAvailable(false);
-            clearNotification();
         }
     }
 
@@ -719,7 +530,8 @@
         public void enter() {
             if (DBG) logd(getName());
             //Start listening every time we get inactive
-            mWifiNative.p2pListen();
+            //TODO: Fix listen after driver behavior is fixed
+            //mWifiNative.p2pListen();
         }
 
         @Override
@@ -737,6 +549,8 @@
                         //TODO: if failure, remove config and do a regular p2pConnect()
                         mWifiNative.p2pReinvoke(netId, mSavedPeerConfig.deviceAddress);
                     } else {
+                        //Stop discovery before issuing connect
+                        mWifiNative.p2pStopFind();
                         //If peer is a GO, we do not need to send provisional discovery,
                         //the supplicant takes care of it.
                         if (isGroupOwner(mSavedPeerConfig.deviceAddress)) {
@@ -1114,7 +928,7 @@
                     }
                     // Do the regular device lost handling
                     return NOT_HANDLED;
-                case WifiP2pManager.DISABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P:
                     sendMessage(WifiP2pManager.REMOVE_GROUP);
                     deferMessage(message);
                     break;
@@ -1494,54 +1308,5 @@
         Slog.e(TAG, s);
     }
 
-    private void showNotification() {
-        NotificationManager notificationManager =
-            (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-        if (notificationManager == null || mNotification != null) {
-            return;
-        }
-
-        Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
-
-        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
-
-        Resources r = Resources.getSystem();
-        CharSequence title = r.getText(R.string.wifi_p2p_enabled_notification_title);
-        CharSequence message = r.getText(R.string.wifi_p2p_enabled_notification_message);
-
-        mNotification = new Notification();
-        mNotification.when = 0;
-        //TODO: might change to be a seperate icon
-        mNotification.icon = R.drawable.stat_sys_tether_wifi;
-        mNotification.defaults &= ~Notification.DEFAULT_SOUND;
-        mNotification.flags = Notification.FLAG_ONGOING_EVENT;
-        mNotification.tickerText = title;
-        mNotification.setLatestEventInfo(mContext, title, message, pi);
-
-        notificationManager.notify(mNotification.icon, mNotification);
-    }
-
-    private void clearNotification() {
-        NotificationManager notificationManager =
-            (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-        if (notificationManager != null && mNotification != null) {
-            notificationManager.cancel(mNotification.icon);
-            mNotification = null;
-        }
-    }
-
-    private boolean isAirplaneSensitive() {
-        String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_RADIOS);
-        return airplaneModeRadios == null
-            || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
-    }
-
-    private boolean isAirplaneModeOn() {
-        return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
-    }
-
     }
 }